You may read guidelines that say: "never use an object as return value of a function. Because of performance reasons". Because the object is copied into the receiving variable when returning from the function call. That was true in C++98. In modern C++, this is no longer true.
Initially (the old days):
- the return object was locally constructed in your function
- it was copied (via copy constructor) into the receiving variable
- the function-local original object was destructed
Now (since 10 years):
- the return object is directly constructed, on location, in the receiving variable
This behaviour (copy elision) is not optional, or an optimiser choice. C++ compilers have to do that for C++ standard 17 and later (i.e.: from GCC 7.x on).
Example code:
#include <iostream> using std::cout; using std::endl; struct T { int value; T(int value); // ctor ~T(); // dtor }; T::T(int value) : value(value) { cout << "ctor" << endl; } T::~T() { cout << "dtor" << endl; } inline T work() { // this object is constructed in place in the variable that's receiving this value (modern c++) // it is not created as a function-local variable, then copied and discarded (old days) return T(1); } int main() { T t = work(); return 0; }
You 'll notice that the object is constructed once. It's constructed by function work() directly on location in the memory area of variable t.
No copying, or destroying. It's just one object that's available to the caller after the function returns.
It will be destroyed when variable t goes out of scope: when main() exits.
In essence, the code above is using the same assembler as:
int main() { T t (1); return 0; }
Run both versions of main(), and check in the output how many times the constructor and destructor are called. Is one more expensive than the other?
Next post: how to efficiently move objects in a program, while avoiding copying large data members.
hint: you can "move" members from one object to the other, instead of "copy, then destroy source"
Thank you for reading.
C++ moving and returning objects part 1: object as return value (embedded friendly C++)
C++ moving and returning objects part 2: move and copy (embedded friendly C++)