在堆栈上使用 placement new with variable 是否正确?

Is using placement new with variable on the stack is correct?

让我们看一下这段代码:

A a(123);
new(&a) A(124);

测试表明,在这种情况下,当程序关闭时,析构函数 ~A() 将被调用一次。因此,如果在 A 中我们有一些指针作为字段,我们将发生内存泄漏。

A a(123);
a.~A();
new(&a) A(124); 

这里都是正确的。但是根据标准,在析构函数调用之后使用对象是未定义的行为(尽管大多数编译器提供的行为没有一些麻烦)。

我可以取一个被调用析构函数的对象的地址吗? 在堆栈变量上调用 placement new 是正确的操作吗?

Can I take an address of object which destructor has been called?

[编辑:] 这样的地址是有效的,因此如果您有指向它的指针,它就是有效的。
事后能不能给个地址,我不太清楚

basic.life.6 […] After the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object was located may be used but only in limited ways. […] Such a pointer refers to allocated storage, and using the pointer as if the pointer were of type void* is well-defined.

查看所有限制的全文,但允许在 placement-new 中使用。


至于评论,我认为你的两个样本在你展示的范围内都是正确的。

A a(123);
new(&a) A(124);

根据我们在样本中所知道的,我认为这是正确的。

根据 basic.life.5,通过重新使用其存储来结束对象的生命周期是有效的。唯一的条件是该程序不依赖于析构函数产生的副作用——为了安全起见,我只会在微不足道的可破坏类型上这样做。否则你需要一个显式的析构函数调用,就像你在那里所做的那样:

A a(123);
a.~A();
new(&a) A(124); 

我没有看到任何规则阻止这种情况。该标准甚至明确提到这种构造何时无效:

If a program:

  • ends the lifetime of an object of type T with static, thread, or automatic storage duration
  • and another object of the original type does not occupy that same storage location when the implicit destructor call takes place,

the behavior of the program is undefined.

(格式为我的要点)

虽然不是明确的证据,但这段话表明在其他情况下,行为是有定义的。我想不出他会违反的另一条规则。

(请注意我使用标准的C++20版本)

是的,这个用法是有效的。对象的存储独立于对象的生命周期。
通过调用析构函数,您将结束对象的生命周期,但这并不意味着释放存储空间。

根据标准,该存储可以重复使用或释放​​。而你所做的就是重复使用它。
basic.life#8

中的标准明确定义了这种情况

请记住,因为 'a' 是一个具有自动存储的变量,所以在作用域的末尾将调用该变量类型的析构函数。