在堆栈上使用位置新变量是正确的吗?



让我们看一下这段代码:

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

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

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

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

可以接受被调用析构函数的对象的地址吗?在堆栈变量上调用新位置是正确的操作吗?

我可以接受被调用析构函数的对象的地址吗?

[编辑:]这样的地址是有效的,所以如果你有一个指向它的指针,它就是有效的。
事后你能记下它的地址吗?我不能完全肯定。

basic.life。在一个对象的生命周期结束后,在该对象所占用的存储空间被重用或释放之前,任何表示该对象所在存储空间地址的指针都可以被使用,但使用方式有限。[…]这样的指针指的是已分配的存储空间,并且将指针当作void*类型的指针使用是定义良好的。

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


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

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

我认为,考虑到我们在样本中所知道的,这是正确的。

根据basic.life.5,通过重用对象的存储来结束对象的生命周期是有效的。唯一的条件是程序不依赖析构函数产生的副作用——为了安全起见,我只会对普通的可析构类型这样做。否则就需要显式地调用析构函数,就像刚才那样:

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

我没有看到任何规则禁止这样做。该标准甚至明确地提到当这样的构造无效时:

如果程序:

  • 以静态、线程或方式结束T类型对象的生命周期自动保存期限
  • 和另一个原始类型的对象不占用相同的空间发生隐式析构函数调用时的存储位置,

程序的行为未定义。

(格式为项目符号)

虽然不是一个明确的证据,但这篇文章表明,在其他情况下,行为是被定义的。我想不出他还会违反其他规则。

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

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

根据标准,该存储可以被重用或释放。你要做的就是重复使用它。
这种情况在基本生活#8的标准中有明确的定义

请记住,因为'a'是一个自动存储的变量,在作用域结束时,将调用该变量类型的析构函数。

最新更新