[Development] Setters: Passing by value or const reference?

Olivier Goffart olivier at woboq.com
Wed Apr 25 12:12:22 CEST 2012


Hi,

In Qt, we traditionally uses const reference as parameter for all our setters.  
This is indeed probably the most efficient thing to do for non-POD in C++98 
since it avoids copy.  But the situation is different in C++11


But first, some reminders of the cost of copies.

In Qt, most of our objects are shared,  meaning a copy is cheap: atomically 
increment the reference count (which will be decremented later when the 
previous object is destroyed).

But in C++11, the concept of move has been introduced, and move is even 
cheaper, it is a simple swap of pointers for types that implement the move 
operators. This is faster than a copy, and generates much less code.

 ჻

Setters in Qt looks like this:

void Foo::setText(const QString &text) {
	d_ptr->text = text; // here a copy
}

foo->setText(tr("hello world")); // no copy here, since we pass by reference.


But wait... tr() returns a temporary so the move could be used somehow...

We could implement a move setter (Foo::setText(QString&&)).  But that would 
mean  duplication, and it could not be inline (access to d_ptr) so binary 
incompatibility between Qt compiled with or without C++11.

The solution is actually much simpler:

void Foo::setText(QString text) {
	d_ptr->text = std::move(text);  // no copy
}

foo->setText(tr("hello world")); // no copy here, this is a move.

Now you don't have any copy: you saved two atomic operations (increment, 
decrement) and generated less code.
If you pass something that is not a temporary, you still have only one copy, 
but on the caller.

 ჻

You notice the use of std::move,  which we can use only in C++11.
Hence the introduction of a qMove macro[1]
https://codereview.qt-project.org/24444
Which would lead to that pattern:

void Foo::setText(QString text) {	d_ptr->text = qMove(text); }


The problem is that this code might be slightly slower in some cases in C++98 
due to the additional copy if qMove is not supported by the compiler.
But the idea is that C++11 is going to be more widely adopted really soon. 
(And it is much faster according to my benchmark http://paste.kde.org/463334 )


It is a bit late now to change all the existing setters for Qt 5.0.
But shall we change the default convention for future setters (and in general 
any function that need to do a copy)?


-- 
Olivier



More information about the Development mailing list