Fabio A. Fabio A. - 1 year ago 60
C++ Question

Why is constructor being elided for this unnamed temporary with side effects with normal initialization but not with braced list initialization?

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?

Answer Source

This is most vexing parse issue: Holder(Test()); declares a function named Test that returns Holder and accepts 0 arguments.

An easy fix is to use C++11 braces for initialization: Holder(Test{}); or Holder{Test{}};.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download