The quote you mention is specifically for returning a reference from a function and binding that reference to a temporary:
const T& f() { return T(); };
That is not the case in your code because you are binding a temporary to a reference at the call side, not in the return statement. In your comments you mention that when you modify the code to:
T f() { return T(); }
T&& r = f();
the lifetime is still extended, but that is wrong. The temporary lives for the duration of the return
statement during which it gets copied to the returned value. After the copy completes the lifetime of the temporary ends. On the calling side you have a different temporary (the result of f()
) whose lifetime gets extended.
But there's no doubt that the lifetime of temporaries are extended. If you define a destructor for class A with any message, it will be printed at the end of main(), or is there?
That statement is also incorrect. You are seeing the effects of the return value optimization (RVO). Instead of creating a temporary for the T()
inside the function and another for the returned value, the compiler is creating the two objects in the same location. You are probably seeing a single object in the output of the program, but in theory there are two.
You can try using g++ with -fno-elide-constructors and you should be able to see both temporaries, one of which is extended the other will not be.
Alternatively, you can return a reference:
const A& f() { return A(); }
const A& r = f();
Which should show how the temporary dies before r
goes out of scope.
This is basically the same test inhibiting the
$ g++ --version | head -1
g++ (GCC) 4.3.2
$ cat x.cpp
#include <iostream>
struct X {
X() { std::cout << "X\n"; }
~X() { std::cout << "~X\n"; }
};
X f() { return X(); }
int main() {
const X& x = f();
std::cout << "still in main()\n";
}
$ g++ -o t1 x.cpp && ./t1
X
still in main()
~X
$ g++ -fno-elide-constructors -o t2 x.cpp && ./t2
X
~X
still in main()
~X
$ clang++ -version | head -1
$ clang version 3.2 (tags/RELEASE_32/final)
$ clang++ -fno-elide-constructors -o t3 x.cpp && ./t3
X
~X
still in main()
~X
$ cat y.cpp
#include <iostream>
struct X {
X() { std::cout << "X\n"; }
~X() { std::cout << "~X\n"; }
};
const X& f() { return X(); }
int main() {
const X& x = f();
std::cout << "still in main()\n";
}
$ g++ -fno-elide-constructors -o t4 y.cpp && ./t4
X
~X
still in main()
A const& f(){ return A(); }
– Xeoreturn <temporary>;
, not assigning the return value of a function to a reference. – David Brown