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:
Y
is called before end of the scope?X::foo()
was called instead of Y::foo()
?X
is run twice?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.
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.
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.
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.
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"});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With