kna*_*ten 9 c++ placement-new object-lifetime undefined-behavior language-lawyer
我试图弄清楚以下是否是未定义的行为.我觉得这不是UB,但我对标准的阅读使它看起来像是UB:
#include <iostream>
struct A {
A() { std::cout << "1"; }
~A() { std::cout << "2"; }
};
int main() {
A a;
new (&a) A;
}
Run Code Online (Sandbox Code Playgroud)
引用C++ 11标准:
basic.life4说"程序可以通过重用对象占用的存储来结束任何对象的生命周期"
所以之后new (&a) A,原始A对象已经结束了它的生命周期.
class.dtor11.3表示"当创建对象的块退出时,将为具有自动存储持续时间([basic.stc.auto])的构造对象隐式调用析构函数([stmt.dcl])"
因此,退出A时会隐式调用原始对象的析构函数main.
class.dtor15说"如果为生命周期结束的对象([basic.life])调用析构函数,则行为是不确定的."
所以这是未定义的行为,因为原始A不再存在(即使新的a现在存在于同一存储中).
问题是是否A调用了原始的析构函数,或者是否调用了当前命名a的对象的析构函数.
我知道basic.life7,它表示名称a是指放置后的新对象new.但是class.dtor11.3明确地说它是对象的析构函数,它退出被调用的作用域,而不是从作用域的名称引用的对象的析构函数.
我误读了标准,还是这个实际上是未定义的行为?
编辑:有几个人告诉我不要这样做.为了澄清,我绝对不打算在生产代码中这样做!这是针对CppQuiz问题,这是关于极端情况而不是最佳实践.
你误读了它.
"对于构造对象隐式调用析构函数"......意味着存在它们并且它们的存在已经完全构建.虽然可以说没有完全拼写出来,但是A它不符合这个标准,因为它不再是"构造的":它根本不存在!只有新的/替换对象会被自动销毁,然后,最后main,正如您所期望的那样.
否则,这种新的布局形式将非常危险并且在语言中具有可争议的价值.然而,值得指出的是,A以这种方式重新使用实际有点奇怪和不寻常,如果没有其他原因导致只是这样的问题.通常,您将new-placement放入一些平淡的缓冲区(如一个char[N]或一些对齐的存储),然后自己也调用析构函数.
实际上可以在basic.life上找到类似于你的例子的东西.它是UB,但只是因为有人构建了T一个B; 措辞清楚地表明这是代码的唯一问题.
但这是关键:
在本国际标准中归于对象的属性仅在其生命周期内适用于给定对象.[..] [ basic.life3 ]
我是否误读了标准,或者这实际上是未定义的行为?
这些都没有。标准不明确,但可以更清楚。目的是调用新对象的析构函数,正如 [basic.life]p9 中暗示的那样。
[class.dtor]p12 不是很准确。我向 Core 询问了这件事,Mike Miller(一位非常资深的成员)说:
I wouldn't say that it's a contradiction [[class.dtor]p12 vs [basic.life]p9], but clarification is certainly needed. The destructor description was written slightly naively, without taking into consideration that the original object occupying a bit of automatic storage might have been replaced by a different object occupying that same bit of automatic storage, but the intent was that if a constructor was invoked on that bit of automatic storage to create an object therein - i.e., if control flowed through that declaration - then the destructor will be invoked for the object presumed to occupy that bit of automatic storage when the block is exited - even it it's not the "same" object that was created by the constructor invocation.
一旦发布,我将使用 CWG 问题更新此答案。因此,您的代码没有 UB。