我有以下基本代码:
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)
归档时间: |
|
查看次数: |
939 次 |
最近记录: |