我有以下基本代码:
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;
};
Run Code Online (Sandbox Code Playgroud)
4个测试用例:
只是Y =好的
const X& var = Y{"temporaryY"};
var.foo();
Run Code Online (Sandbox Code Playgroud)
结果:
X::X() // base temporaryY
Y::Y() // temporaryY
Y::foo()
Y::~Y() // temporaryY
X::~X() // base temporaryY
Run Code Online (Sandbox Code Playgroud)
只是X =好的
const X& var = X{"temporaryX"};
var.foo();
Run Code Online (Sandbox Code Playgroud)
结果:
X::X() // temporaryX
X::foo()
X::~X() // temporaryX
Run Code Online (Sandbox Code Playgroud)
Y或X通过功能 =确定
const X& var = factory();
var.foo();
Run Code Online (Sandbox Code Playgroud)
结果:
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
Run Code Online (Sandbox Code Playgroud)
Y或X通过三元运营商 = WTF?!
const X& var = false ? X{"temporaryX"} : Y{"temporaryY"};
var.foo();
Run Code Online (Sandbox Code Playgroud)
结果:
X::X() // base temporaryY
Y::Y() // temporaryY
Y::~Y() // temporaryY
X::~X() // base temporaryY
X::foo()
X::~X() // base temporaryY
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么七个地狱:
Y在范围结束之前调用析构函数?X::foo()被叫而不是Y::foo()?X函数运行两次?Mar*_*k B 11
你所缺少的是你的临时文件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"});
Run Code Online (Sandbox Code Playgroud)