Reputation: 2724
I wanted to test whether a temporary object would live at least as long as the temporary object that held a const reference to it, so I came up with this example.
#include <iostream>
struct Test {
Test() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
~Test() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
struct Holder {
Holder(const Test& t):m_t(t) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
~Holder() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
const Test& m_t;
};
int main() {
Holder(Test());
return 0;
}
However, I was quite surprised to see that the compiler had actually optimized out the whole thing, as can be seen on codebolt
But, if I actually give a name to the temporary, by changing the line
Holder(Test());
into
Holder h((Test()));
Then it "magically" works: codebolt.
Plot twist: if I switch to c++11 and use the braced list initialization for the Holder
class, then the constructor is not elided no matter whether I give a name to the temporary or not. See codebolt again.
So what's the matter here? I was under the impression that constructors with side effects would never be elided, but I'm obviously missing an important piece of the standard that changed between versions.
Can anybody give me a hint?
Upvotes: 3
Views: 167
Reputation: 136256
This is most vexing parse issue: Holder(Test());
declares a function named Test
that returns Holder
and accepts 0 arguments.
With g++ the following code:
#include <iostream>
#include <type_traits>
struct Test {};
struct Holder { Holder(Test); };
template<class T>
char const* f() { return __PRETTY_FUNCTION__; }
int main() {
Holder(Test());
std::cout << f<decltype(&Test)>() << '\n';
}
Outputs:
const char* f() [with T = Holder (*)()]
An easy fix is to use C++11 braces for initialization: Holder(Test{});
or Holder{Test{}};
.
Upvotes: 6