使用"placement new"创建的对象是否具有动态存储期限? [英] Does an object created with placement new have dynamic storage duration?

查看:108
本文介绍了使用"placement new"创建的对象是否具有动态存储期限?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(5.3.4)

新表达式:

  • :: opt _ 新的新展示位置_ opt 新类型标识new-initializeropt

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

:: opt _ 新的新展示位置_ opt (type-id)new-initializeropt

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

通过新表达式创建的实体具有动态存储期限 (3.7.4). [注意:这样的实体的生存期不一定 仅限其创建范围. —尾注]

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个具有动态存储时间的虚拟类. /p>

I think the following has 1 main object (local_object) with automatic storage duration, and 3 dummy classes with dynamic storage duration.

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),其余的只是指针.这是正确的吗?

The user @M.M. argues that there's only one object (local_object), and that the rest are just pointers. Is this correct?

(3.7)

动态存储期限与使用 operator new

推荐答案

在我看来,标准(如OP中所引用)只能在其读取时进行解释,即 operator new创建对象.动态存储持续时间,即使为自动持续时间的对象获取了基础内存也是如此.

It seems to me that the standard (as quoted in the OP) can only be interpreted as it reads, which is that operator new creates objects of dynamic storage duration, and this is true even if the underlying memory was obtained for an object of automatic duration.

§ 3.8 [basic.life]第8段中的标准预期了这种精确的情况,并参考以下未定义行为的示例:

This precise scenario is anticipated by the standard in §3.8 [basic.life] paragraph 8, with reference to the following example of undefined behaviour:

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

该段内容为:

如果程序以静态(3.7.1),线程(3.7.2)或自动(3.7.3)存储持续时间结束类型T的对象的生存期,并且如果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段所提供:(强调).

In the example, the program has "ended the lifetime" of the object b by reusing its storage, as provided by paragraph 4 of the same section: (emphasis added).

程序可以通过重用该对象占用的存储空间或通过显式调用具有非平凡析构函数的类类型对象的析构函数来结束任何对象的生命周期.

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段明确允许不调用非平凡的析构函数:

In the example code, b's destructor was not called but this is acceptable because paragraph 4 explicitly allows a non-trivial destructor to not be called:

对于具有非平凡析构函数的类类型的对象,在重用或释放该对象占用的存储空间之前,程序无需显式调用析构函数;

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;

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

as long as the program is prepared to live with the consequences of the destructor not being called.

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

But to return to paragraph 8, b's lifetime has ended, and the storage has been reused to create an object of type T. This object has dynamic storage duration, which means that its destructor will not be called implicitly. As above, it is not obligatory to explicitly call the destructor either, as long as the program does not require any side-effects which might be performed by the destructor.

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

Despite the fact that the lifetime of b has ended, the fact that b had automatic storage duration means that its destructor will be implicitly called when control flow leaves its scope. Calling a destructor on an object whose lifetime has ended is a specific case of the prohibition on using an object whose lifetime has ended, as per paragraph 6 of §3.8, which prohibits calling a non-static member member function of an object whose lifetime has ended but whose storage has not yet been reused or released.

由于这个原因,示例程序的行为是不确定的.

For this reason, the example program's behaviour is undefined.

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

But paragraph 7 of this section provides a mechanism for the program to avoid the undefined behaviour by recreating a different object of the same type at the same location:

如果在一个对象的生命周期结束之后并且在重新使用或释放​​该对象所占用的存储之前,在原始对象所占用的存储位置上创建了一个指向原始对象的指针的新对象,引用原始对象的引用或原始对象的名称将自动引用新对象,并且一旦开始新对象的生存期,就可以使用它来操作新对象,如果:

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)-新对象的存储位置正好覆盖了原始对象所占据的存储位置,并且

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

(7.2)-新对象与原始对象具有相同的类型(忽略顶级cv限定词),并且

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

(7.3)—原始对象的类型不是const限定的,并且,如果是类类型,则不包含任何类型为const限定的非静态数据成员或引用类型,并且

(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)-原始对象是类型T的最大派生对象(1.8),而新对象是类型T的最大派生对象(也就是说,它们不是基类的子对象).

(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).

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

So, in my interpretation, the following snippet would have defined behaviour:

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

简而言之,该标准考虑了可以使用分配给自动存储持续时间的对象的内存来创建动态存储持续时间的对象的可能性,并为执行此操作的定义良好的程序提供了一组限制和要求. ,从而避免了对通过重新使用其存储而终止生命的对象执行隐式析构函数的后果.

In short, the standard contemplates the possibility that an object of dynamic storage duration can be created using memory allocated to an object of automatic storage duration, and provides a set of restrictions and requirements for a well-defined program which performs this action, thereby avoiding the consequences of executing an implicit destructor on an object whose lifetime has been ended by reusing its storage.

这篇关于使用"placement new"创建的对象是否具有动态存储期限?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆