C++ 使用放置新的未定义行为构造对象两次
C++ Is constructing object twice using placement new undefined behaviour?
我遇到了一些让我感到恐惧的代码。本质上它遵循以下模式:
class Foo
{
public:
//default constructor
Foo(): x(0), ptr(nullptr)
{
//do nothing
}
//more interesting constructor
Foo( FooInitialiser& init): x(0), ptr(nullptr)
{
x = init.getX();
ptr = new int;
}
~Foo()
{
delete ptr;
}
private:
int x;
int* ptr;
};
void someFunction( FooInitialiser initialiser )
{
int numFoos = MAGIC_NUMBER;
Foo* fooArray = new Foo[numFoos]; //allocate an array of default constructed Foo's
for(int i = 0; i < numFoos; ++i)
{
new( fooArray+ i) Foo( initialiser ); //use placement new to initialise
}
//... do stuff
delete[] fooArray;
}
这段代码已经在代码库中存在多年,似乎从未引起过问题。这显然是一个坏主意,因为有人可以更改默认构造函数以分配不期望第二个构造。简单地用等效的初始化方法替换第二个构造函数似乎是明智的做法。
void Foo::initialise(FooInitialiser& init)
{
x = init.getX();
ptr = new int;
}
尽管仍然受到可能的资源泄漏的影响,但至少防御性程序员可能会考虑以正常方法检查先前的分配。
我的问题是:
像这样两次构造实际上是未定义的行为/被标准禁止还是只是一个坏主意?如果不确定的行为,您可以引用或指出我正确的位置来查看标准吗?
通常,以这种方式使用放置新位置不是一个好主意。从第一个 new 调用初始值设定项,或调用初始值设定项而不是放置 new,都被认为比您提供的代码更好。
但是,在这种情况下,在现有对象上调用放置 new 的行为是明确定义的。
程序可以通过重用存储来结束任何对象的生存期 对象占据的或通过显式调用析构函数 具有非平凡析构函数的类类型的对象。对于对象 具有非平凡析构函数的类类型,该程序不是 需要在存储之前显式调用析构函数 对象被重用或释放;但是,如果没有 显式调用析构函数,或者如果删除表达式 (5.3.5( 是 不用于释放存储,析构函数不得 隐式调用和任何依赖于副作用的程序 析构函数生成的行为未定义。
因此,当这种情况发生时:
Foo* fooArray = new Foo[numFoos]; //allocate an array of default constructed Foo's
for(int i = 0; i < numFoos; ++i)
{
new( fooArray+ i) Foo( initialiser ); //use placement new to initialise
}
放置新操作将结束存在的Foo
的生存期,并在其位置创建一个新操作。在许多情况下,这可能很糟糕,但考虑到析构函数的工作方式,这很好。
在现有对象上调用放置 new 可能是未定义的行为,但这取决于特定对象。
这不会产生未定义的行为,因为您不依赖于析构函数产生的"副作用"。
对象的析构函数中唯一的"副作用"是delete
包含的int
指针,但在这种情况下,当调用放置new
时,该对象永远不会处于可删除状态。
如果包含的 int
指针可能等于 nullptr
以外的其他内容,并且可能需要删除,则在现有对象上调用放置new
将调用未定义的行为。
- C++析构函数调用两次,堆栈分配的复合对象
- C++两次从文件保存对象读取多重继承
- 在条件运算符中使用对象两次会产生 UB 吗?
- 为什么我的对象似乎被创建了两次
- 为什么静态thread_local对象在C++构造两次
- 如何在同一个线程上用同一个互斥对象锁定两次
- 为什么在 C++ 中,当对象包含在另一个对象中时,复制构造函数被调用两次
- 两次构造对象
- 删除对象两次
- C++-如果我使用映射,我的对象会被删除两次吗
- 在Qt 5.4中可以对互斥对象进行两次解锁吗
- 如何正确地将对象添加到向量,而无需两次调用析构函数
- 静态 c++ 对象中的 JNI 环境指针并调用连续两次使用字符串参数的 Java 函数会使 JVM 崩溃
- C++ 使用放置新的未定义行为构造对象两次
- 在为对象调用析构函数时,它被调用两次
- 使用默认构造函数返回临时对象时,Destuctor调用了两次
- c++如何初始化对象?下面的情况是这样做两次吗
- 对于在同一地址构造两次的对象,编译器如何知道必须调用第二个析构函数
- 在链接两个对象文件时,使用#ifndef防止定义一个函数两次
- Java - Can调用系统.Gc两次,释放底层对象两次