我有以下基本代码:
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; };
4个测试用例:
只是Y =好的
const X& var = Y{"temporaryY"}; var.foo();
结果:
X::X() // base temporaryY Y::Y() // temporaryY Y::foo() Y::~Y() // temporaryY X::~X() // base temporaryY
只是X =好的
const X& var = X{"temporaryX"}; var.foo();
结果:
X::X() // temporaryX X::foo() X::~X() // temporaryX
Y或X via function = OK
const X& var = factory(); var.foo();
结果:
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或X通过三元运算符= WTF ?!
const X& var = false ? X{"temporaryX"} : Y{"temporaryY"}; var.foo();
结果:
X::X() // base temporaryY Y::Y() // temporaryY Y::~Y() // temporaryY X::~X() // base temporaryY X::foo() X::~X() // base temporaryY
有人可以解释为什么七个地狱:
解决方法
你缺少的是你的临时Y正在通过切片复制构造成一个隐藏的临时X,它绑定到你的const引用.那就是你看到的最终析构函数,也解释了为什么Y比预期更早被破坏.这个副本的原因是三元运算符的“返回”只是一种类型. X不可能被视为Y,因此X是要使用的常见类型,从而引起额外的临时X对象.
请注意,这与“Just Y”测试用例不同,因为在该实例中创建了Y临时,然后立即尝试绑定到const X&这是允许的.在三元情况下,运算符本身会引入运算符操作数的公共对象类型的中间切片,在本例中为X.
我相信你可以通过转换为父引用来避免临时切片,但是我没有访问C 11编译器来测试它(除了问题中有些不完整的代码):
const X& var = false ? X{"temporaryX"} : static_cast<const X&>(Y{"temporaryY"});