我可以通过引用调用placement-new和析构函数吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我可以通过引用调用placement-new和析构函数吗?相关的知识,希望对你有一定的参考价值。

我可以传递对未初始化内存的引用,获取地址,然后调用placement-new或在获取的内存位置调用析构函数。换句话说,以下程序是合法的C ++还是具有未定义的行为:

#include <string>
#include <iostream>

void ctor (std::string &s)
{
  new (&s) std::string ("Hello, world!");
}

void dtor (std::string &s)
{
  (&s)->std::string::~string ();
}

int main ()
{
  std::string * memory = static_cast<std::string *> (
    operator new (sizeof (std::string) * 10));

  ctor (memory [0]);

  std::cout << memory [0] << '
';

  dtor (memory [0]);

  operator delete (memory);
}

当然,它有效,我尝试了gcc的未定义行为消毒剂,它没有产生任何错误。但任何人都可以根据标准确认/反驳。

答案

上面的代码在[0]上双重构造一个字符串,这是一个潜在的资源泄漏,而double会破坏它,这是未定义的行为。

new string[10]在数组中构造对象。 delete[]摧毁了这些物体。你在另一个上面创建一个新对象,然后销毁它,然后当你delete[]时再次销毁它。

没有其他错误;我的意思是它使用原始分配,这通常是不好的做法,代码是异常不安全的等等。

另一答案
dtor (memory [0]);

delete [] memory;

肯定是未定义的行为。

行中构造的对象的生命周期

std::string * memory = new std::string [10];

当您使用placement new运算符时结束。

因此,

delete [] memory;

是未定义的行为。

更新

更新的代码行

dtor (memory [0]);

operator delete (reinterpret_cast<void *> (memory));

表现得很好。

分配有placement new运算符的对象的析构函数只调用一次。

operator new调用分配的内存由operator delete调用取消分配。

另一答案

编辑后,似乎不再存在未定义的行为。

但是,您的代码仍然存在危险: 你的memory变量具有指向构造字符串的指针类型,即使指针初始化后该指针后面没有字符串。指针也不是nullptr。这很危险。您正在向编译器断言某些东西是正确构造的对象,而不是。因此,您的编译器不会错误地使用未构造的对象。

我强烈建议使用char*变量跟踪未初始化的内存,并且只对已经正确构造的对象使用类型类型的指针。

以上是关于我可以通过引用调用placement-new和析构函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

条款09:不要在构造过程和析构过程中调用 virtual 方法

条款09:不要在构造过程和析构过程中调用 virtual 方法

Excel VBA 对象构造函数和析构函数

php构造函数的PHP 5 构造函数和析构函数

[类和对象]构造和析构

C++ 堆栈分配的对象赋值和析构函数调用