gpt4 book ai didi

c++ - 使用 placement new 创建的对象是否具有动态存储持续时间?

转载 作者:可可西里 更新时间:2023-11-01 16:38:05 25 4
gpt4 key购买 nike

(5.3.4)

new-expression:

  • ::opt_new new-placement_opt new-type-id new-initializeropt

  • ::opt_new new-placement_opt ( type-id ) new-initializeropt

Entities created by a new-expression have dynamic storage duration (3.7.4). [ Note: the lifetime of such an entity is not necessarily restricted to the scope in which it is created. — end note ]

我认为以下有 1 个具有自动 存储持续时间的主要对象 (local_object),以及 3 个具有动态 存储持续时间的虚拟类。

struct dummy
{
int a;
};

char local_object[256];
dummy * a = new(&local_object) dummy;
dummy * b = new(&local_object +100) dummy;
dummy * c = new(&local_object +200) dummy;

用户@M.M.认为只有一个对象(local_object),其余的只是指针。这是正确的吗?

(3.7)

The dynamic storage duration is associated with objects created with operator new

最佳答案

在我看来,标准(如 OP 中引用的那样)只能按其读取的方式进行解释,即 operator new 创建动态存储持续时间的对象,即使底层内存是为自动持续时间的对象获取的。

引用以下未定义行为的示例,§3.8 [basic.life] 第 8 段中的标准预期了这种精确场景:

class T { };
struct B {
~B();
};
void h() {
B b;
new (&b) T;
}

该段内容如下:

If a program ends the lifetime of an object of type T with static (3.7.1), thread (3.7.2), or automatic (3.7.3) storage duration and if T has a non-trivial destructor, the program must ensure that an object of the original type occupies that same storage location when the implicit destructor call takes place; otherwise the behavior of the program is undefined.

在示例中,程序通过重用其存储“结束了对象 b 的生命周期”,如同一部分第 4 段所提供的:(强调已添加)。

A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor.

在示例代码中,b 的析构函数未被调用,但这是可以接受的,因为第 4 段明确允许不调用非平凡的析构函数:

For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released;

只要程序准备好承受未调用析构函数的后果。

但回到第 8 段,b 的生命周期已经结束,并且存储已被重用以创建类型为 T 的对象。该对象具有动态存储持续时间,这意味着它的析构函数不会被隐式调用。如上所述,也不必显式调用析构函数,只要程序不需要析构函数可能执行的任何副作用即可。

尽管 b 的生命周期已经结束,但 b 具有自动存储持续时间这一事实意味着当控制流离开其作用域时,其析构函数将被隐式调用.在生命周期结束的对象上调用析构函数是禁止使用生命周期结束的对象的特定情况,根据 §3.8 的第 6 段,它禁止调用生命周期已经结束的对象的非静态成员函数结束但其存储尚未被重用或释放。

因此,示例程序的行为是未定义的。

但是本节的第 7 段提供了一种机制,可以让程序通过在同一位置重新创建同一类型的不同对象来避免未定义的行为:

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:

(7.1) — the storage for the new object exactly overlays the storage location which the original object occupied, and

(7.2) — the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and

(7.3) — the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and

(7.4) — the original object was a most derived object (1.8) of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).

因此,根据我的解释,以下代码段将定义行为:

class T { };
struct B {
~B();
};
void h() {
B b;
new (&b) T;
new (&b) B; /* recreate a B so that it can be destructed */
}

简而言之,该标准考虑了使用分配给自动存储持续时间对象的内存创建动态存储持续时间对象的可能性,并为执行此操作的明确定义的程序提供了一组限制和要求,从而避免在生命周期已结束的对象上执行隐式析构函数的后果,方法是重用其存储空间。

关于c++ - 使用 placement new 创建的对象是否具有动态存储持续时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35389789/

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