Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why passing a QStringView by value is faster than a reference-to-const?

Tags:

c++

qt

I have found this in Qt's Doc:

QStringViews should be passed by value, not by reference-to-const:

and they give the following example:

void myfun1(QStringView sv);        // preferred
void myfun2(const QStringView &sv); // compiles and works, but slower

How is this possible?

like image 983
Fryz Avatar asked Sep 17 '18 09:09

Fryz


People also ask

Why is it usually better to pass objects by reference than by value?

The reason is simple: if you passed by value, a copy of the object had to be made and, except for very small objects, this is always more expensive than passing a reference.

Should I pass by value or reference c++?

Use pass-by-reference if you want to modify the argument value in the calling function. Otherwise, use pass-by-value to pass arguments. The difference between pass-by-reference and pass-by-pointer is that pointers can be NULL or reassigned whereas references cannot.

What is the difference between pass by reference and pass by const reference?

From what I understand: when you pass by value, the function makes a local copy of the passed argument and uses that; when the function ends, it goes out of scope. When you pass by const reference, the function uses a reference to the passed argument that can't be modified.

What is QString in Qt?

The QString class provides an abstraction of Unicode text and the classic C '\0'-terminated char array. More... All the functions in this class are reentrant when Qt is built with thread support.


1 Answers

QStringView is typically used in high-performance code where creating actual QString objects would be slow due to the memory allocation involved. I optimized QStringView so that it is as performant as handling a (const QChar*, size_t) manually. I even went to the length of having member function calls hand off inline to free functions, passing *this by value. All this is to avoid forcing QStringView objects onto the stack, or, more generally, into memory.

In virtually all C++ compilers, a QStringView object is represented as a pair of CPU registers, and many C++ ABIs (sadly, excluding Windows) support passing such types in CPU registers to functions. If you wrote the member function naïvely, with an implicit this parameter as the address of the object, calling such a function out-of-line would force the compiler to allocate a QStringView object on the stack to be able to pass its address as the first argument of the member function.

There's a second argument for pass-by-value: there are less aliasing problems. As a reference type, QStringView exhibits that problem anyway, but consider std::complex: Take

std::complex &operator*=(std::complex &lhs, const std::complex &rhs);

(template args omitted for brevity). This can be called like this:

std::complex c = 3 + 4i;
c *= c;

If you naïvely implement operator*= as if it was a mathematical function:

auto r = real(), i = imag();
m_real = r * other.real() - i * other.imag();
m_imag = r * other.imag() + i * other.real();

you would have clobbered other.real() after the first line, thus calculating a wrong result (yes, people do write this code in production). Passing the rhs by value makes the problem go away.

like image 78
Marc Mutz - mmutz Avatar answered Sep 23 '22 01:09

Marc Mutz - mmutz