Reputation: 5167
Consider the following program:
class C {
...
};
const C f() {
C ret;
cout << &ret << endl;
return ret;
}
int main() {
C value = f();
cout << &value << endl;
}
result: // note the address are the same
0x7ffdd24b26e0
0x7ffdd24b26e0
The variable 'ret' in function f() and variable 'value' has the same memory address so it seems 'value' is not a copy of 'ret'. The variable 'ret' is a stack variable so it should be invalidated after f() returns. So why c++ allow returning a stack value inside a function?
g++ version:
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
Upvotes: 1
Views: 103
Reputation: 180265
I'm not sure whether this is actually RVO. An equally valid hypothesis is that the storage of both ret
and value
is on the implementation's stack, and that they share the same stack slot because their lifetimes are effectively non-overlapping. There might have been an intermediary.
Upvotes: 0
Reputation: 21166
Returning the function result by value is one of the places, where the compiler is allowed to elide a copy as an optimization and thus translates your code to the moral equivalent of this :
void f(uint8_t* memory) {
new(memory) C; // create object reserved memory location
cout << (size_t)memory << endl;
}
int main() {
alignas(alignof(C)) uint8_t value[sizeof(C)]; //<- reserve properly aligned raw storage of appropriate size on the stack
f(value);
cout << (size_t)&value[0] << endl;
}
This optimization technique is called NRVO (named return value optimization) and is actually a pretty natural consequence of most calling conventions which specify that - for values that can't be returned via a register - the returned value is put at an address that is specified by the caller anyway.
Upvotes: 1
Reputation: 4016
This is an example of copy-elision, specifically RVO (return value optimization). It allows you to avoid the performance penalty of returning an object.
I've worked with a lot of people who were unaware of RVO and wrote stuff like:
void get_stuff(std::vector<int>& foo /*and input params*/) {
// add a whole lot of integers into foo.
}
because they thought this would be cheaper (by avoiding a copy) than:
void get_stuff(/*input params*/){
std::vector foo;
// populate foo.
return foo;
}
This leads to unnecessarily verbose, and often difficult to read code. It's quintessential premature optimization -- a mistake you won't be making, since you now know about RVO!
Upvotes: 3
Reputation: 27068
The reason for the address of ret and value being the same is the so called Return Value Optimization (RVO). It means that in this case a copy is not going to be performed. Note however, that you can not rely on this, as it is not bound to happen (although that will change with C++17 [at least the current draft]).
https://en.wikipedia.org/wiki/Return_value_optimization
Upvotes: 4