Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Temporaries, references and ternary operator in C++

Tags:

c++

c++11

I've got the following base code:

struct X {
  X(const char* descr) {...}
  ~X() {...} // Not virtual
  virtual void foo() const {...}
};

struct Y : public X {
  Y(const char* descr) {...}
  ~Y() {...} // Not virtual
  virtual void foo() const {...}
};


const X& factory() {
    static X sampleX{"staticX"};
    static Y sampleY{"staticY"};
    return X or Y depending of the test case;
};

And 4 test cases:

Just Y = OK

const X& var = Y{"temporaryY"};
var.foo();

Result:

X::X() // base temporaryY
Y::Y() // temporaryY
Y::foo()
Y::~Y() // temporaryY
X::~X() // base temporaryY

Just X = OK

const X& var = X{"temporaryX"};
var.foo();

Result:

X::X() // temporaryX
X::foo()
X::~X() // temporaryX

Y or X via function = OK

const X& var = factory();
var.foo();

Result:

X::X() // staticX
X::X() // base staticY
Y::Y() // staticY
X::foo() or Y::foo()
Y::~Y() // staticY
X::~X() // base staticY
X::~X() // staticX

Y or X via ternary operator = WTF?!

const X& var = false ? X{"temporaryX"} : Y{"temporaryY"};
var.foo();

Result:

X::X() // base temporaryY
Y::Y() // temporaryY
Y::~Y() // temporaryY
X::~X() // base temporaryY
X::foo()
X::~X() // base temporaryY

Could someone explain me why for the seven hells:

  • Destructor of Y is called before end of the scope?
  • X::foo() was called instead of Y::foo()?
  • Destructor of X is run twice?
like image 344
Red XIII Avatar asked Sep 20 '13 14:09

Red XIII


People also ask

What is an ternary operator in C?

Ternary Operator in C is an operator which takes three operands or variables, unlike the other operators which take one or two operands. Ternary operator in C is also known as Conditional Operator. It is a way to shorten the simple if-else code of the block.

What is ternary operator in C give example?

It helps to think of the ternary operator as a shorthand way or writing an if-else statement. Here's a simple decision-making example using if and else: int a = 10, b = 20, c; if (a < b) { c = a; } else { c = b; } printf("%d", c); This example takes more than 10 lines, but that isn't necessary.

How do you write 3 conditions in a ternary operator?

The conditional (ternary) operator is the only JavaScript operator that takes three operands: a condition followed by a question mark ( ? ), then an expression to execute if the condition is truthy followed by a colon ( : ), and finally the expression to execute if the condition is falsy.

What is the difference between ternary and conditional operator?

Ternary Operator is a three operand conditional operator. It's a simplified if-else statement format. The ternary operator's first operand is a condition, should return a boolean value. The second and third operands are expressions that are executed based on a condition basis.


1 Answers

What you're missing is that your temporary Y is getting copy-constructed-by-slice into a hidden temporary X that's bound to your const reference. That is then the final destructor you see and also explains why the Y is destructed earlier than expected. The reason this copy is made is that the "return" from the ternary operator is only one type. An X can't possibly ever be treated as a Y so X is the common type to be used, thus inducing the extra temporary X object.

Note that this is different from the "Just Y" test case, because in that instance a Y temporary is created and then immediately attempts to bind to a const X& which is allowed. In the ternary case, the operator itself induces an intermediate slice to the common object type of the operators operands, in this case X.

I believe you can avoid the temporary slice by casting to parent reference but I don't have access to a C++11 compiler to test this (in addition to the somewhat incomplete code in the question):

const X& var = false ? X{"temporaryX"} : static_cast<const X&>(Y{"temporaryY"});
like image 73
Mark B Avatar answered Nov 07 '22 23:11

Mark B