gpt4 book ai didi

c++ - 为什么销毁被 placement new 覆盖的对象不是未定义的行为?

转载 作者:可可西里 更新时间:2023-11-01 16:36:06 28 4
gpt4 key购买 nike

我想弄清楚以下是否是未定义的行为。我感觉它不是 UB,但我对标准的阅读使它看起来像是 UB:

#include <iostream>

struct A {
A() { std::cout << "1"; }
~A() { std::cout << "2"; }
};

int main() {
A a;
new (&a) A;
}

引用 C++11 标准:

basic.life¶4说“程序可以通过重用对象占用的存储来结束任何对象的生命周期”

所以在new (&a) A之后,原来的A对象已经结束了它的生命周期。

class.dtor¶11.3说“当创建对象的 block 退出([stmt.dcl])时,为具有自动存储持续时间([basic.stc.auto])的构造对象隐式调用析构函数”

因此当 main 退出时,原始 A 对象的析构函数被隐式调用。

class.dtor¶15表示“如果为生命周期已结束的对象调用析构函数 ([basic.life]),则行为未定义。”

所以这是未定义的行为,因为原始的 A 不再存在(即使新的 a 现在存在于相同的存储中)。

问题是是否调用了原始A 的析构函数,或者是否调用了当前名为a 的对象的析构函数。

我知道 basic.life¶7 ,它表示名称 a 指的是放置 new 之后的新对象。但是 class.dtor¶11.3 明确指出调用的是退出作用域的对象的析构函数,而不是退出作用域的名称引用的对象的析构函数 .

我是不是误读了标准,或者这实际上是未定义的行为?

编辑:有几个人告诉我不要这样做。澄清一下,我绝对不打算在生产代码中这样做!这是一个 CppQuiz问题,这是关于极端情况而不是最佳实践。

最佳答案

你误读了。

“为构造的对象隐式调用析构函数”......意思是那些存在并且它们的存在已经达到完全构造的程度。虽然可以说没有完全拼写出来,但原始的 A 不符合这个标准,因为它不再是“构造的”:它根本不存在!正如您所期望的,只有新的/替换对象会自动销毁,然后在 main 的末尾。

否则,这种放置 new 的形式将非常危险,并且在语言中具有值得商榷的值(value)。然而,值得指出的是,以这种方式重新使用实际的 A 有点奇怪和不寻常,如果没有其他原因,只是它会导致这种问题。通常,您会将 place-new 放入一些平淡的缓冲区(例如 char[N] 或一些对齐的存储),然后您自己也调用析构函数。

实际上可以在 basic.life¶8 找到与您的示例类似的内容— 它是 UB,但只是因为有人在 B 之上构建了 T;措辞非常清楚地表明这是代码的唯一问题。

但关键是:

The properties ascribed to objects throughout this International Standard apply for a given object only during its lifetime. [..] [basic.life¶3]

关于c++ - 为什么销毁被 placement new 覆盖的对象不是未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52153673/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com