放置新的和未初始化的POD成员 [英] Placement new and uninitialized POD members

查看:112
本文介绍了放置新的和未初始化的POD成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++标准是否保证未初始化的POD成员在放置新的之后仍保留其先前的值?

Does the C++ standard guarantee that uninitialized POD members retain their previous value after a placement new?

或者更准确地说,以下断言总是满足C ++ 11?

Or more precisely, will the following assert always be satisfied according to C++11?

#include <cstdlib>
#include <cassert>

struct Foo {
    int alpha; // NOTE: Uninitialized
    int beta = 0;
};

int main()
{
    void* p = std::malloc(sizeof (Foo));
    int i = some_random_integer();
    static_cast<Foo*>(p)->alpha = i;
    new (p) Foo;
    assert(static_cast<Foo*>(p)->alpha == i);
}

C ++ 03的答案是否相同?

Is the answer the same for C++03?

推荐答案


C ++标准是否保证未初始化的POD成员在放置新的之后保留其先前的值?

Does the C++ standard guarantee that uninitialized POD members retain their previous value after a placement new?

根据C ++ 11,以下断言总是会满足吗?

Will the following assert always be satisfied according to C++11?

否。

未初始化的数据成员具有不确定值,这与说底层内存

Uninitialized data members have an indeterminate value, and this is not at all the same as saying that the underlying memory is left alone.


[C ++ 11:5.3.4 / 15]:创建 T 类型的对象的 new-expression 按如下方式初始化该对象:

[C++11: 5.3.4/15]: A new-expression that creates an object of type T initializes that object as follows:


  • 如果省略了 new-initializer ,则对象默认初始化 (8.5)。

  • 否则,根据8.5的初始化规则对直接初始化的 new-initializer 进行解释。

  • If the new-initializer is omitted, the object is default-initialized (8.5); if no initialization is performed, the object has indeterminate value.
  • Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct-initialization.

[C ++ 11:8.5 / 6]:初始化 T 类型的对象意味着:

[C++11: 8.5/6]: To default-initialize an object of type T means:


  • if T (可能是 cv限定)类类型(第9条) T 被调用(如果 T 没有可访问的默认构造函数,初始化是错误的) ;

  • 如果 T 是数组类型,则每个元素都默认初始化;


  • if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • if T is an array type, each element is default-initialized;
  • otherwise, no initialization is performed.

[C ++ 11:12.1 / 6]:当使用 odr使用(3.2)创建一个类类型(1.8)的对象时或者当它被明确地定义时,默认构造函数默认在其第一个声明之后。 隐式定义的默认构造函数执行类的初始化集合,该类将由用户编写的没有 ctor-initializer (12.6)的类的默认构造函数执行

[C++11: 12.1/6]: A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration. The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with no ctor-initializer (12.6.2) and an empty compound-statement.

[C ++ 11:12.6.2 / 8]:在非委托构造函数中,如果给定的非静态数据成员或基类未由em初始化器指定-id (包括没有 mem-initializer-list 的情况,因为构造函数没有 ctor-initializer ),不是抽象类(10.4)的虚拟基类,则

[C++11: 12.6.2/8]: In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then


  • 如果实体是非静态数据成员, em> brace-or-equal-initializer ,实体按8.5中的规定初始化;

  • 否则,如果实体是变量成员

  • if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized as specified in 8.5;
  • otherwise, if the entity is a variant member (9.5), no initialization is performed;
  • otherwise, the entity is default-initialized (8.5).

NB。 12.6.2 / 8 您的成员 beta 已处理)

(NB. the first option in 12.6.2/8 is how your member beta is handled)


[C ++ 11:8.5 / 6]:默认初始化 T 类型的对象意味着:

[C++11: 8.5/6]: To default-initialize an object of type T means:


  • 如果 T 是(可能是 cv限定)类类型),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,初始化将失败);

  • 如果 T 是数组类型,则每个元素都默认初始化;


  • if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • if T is an array type, each element is default-initialized;
  • otherwise, no initialization is performed.

[C ++ 11: 8.5 / 11]:如果没有为一个对象指定初始化器,则该对象被默认初始化; 如果未执行初始化,则具有自动或动态存储持续时间的对象具有不确定的值。

[C++11: 8.5/11]: If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value.

可以选择在分配期间清除(或以其他方式改变)底层内存。例如,Visual Studio在调试模式下已知将可识别的值(例如 0xDEADBEEF )写入内存以帮助调试;在这种情况下,您可能会看到 0xCDCDCDCD ,它们用来表示清理内存(参考)。

A compiler could choose to zero-out (or otherwise alter) the underlying memory during allocation. For example, Visual Studio in debug mode is known to write recognisable values such as 0xDEADBEEF into memory to aid debugging; in this case, you're likely to see 0xCDCDCDCD which they use to mean "clean memory" (reference).

我不知道。我不认为我们可以知道。

我们知道的是C ++不禁止它,我相信,让我们得出这个答案的结论。 :)

What we do know is that C++ doesn't prohibit it, and I believe that brings us to the conclusion of this answer. :)


C ++ 03的答案是否一样?

Is the answer the same for C++03?

,但略有不同的逻辑:

Yes, though through slightly different logic:


[C ++ 03:5.3.4 / 15]:一个新表达式 code> T 初始化该对象,如下所示:

[C++03: 5.3.4/15]: A new-expression that creates an object of type T initializes that object as follows:


  • -initializer is

    • 如果 T (可能是cv限定的)非POD类类型(或其数组),对象被默认初始化(8.5)。如果 T 是一个const限定类型,基础类类型应具有用户声明的默认构造函数。

    • 如果 T 是const限定类型或(可能是cv限定的)POD

    • If the new-initializer is omitted:
      • If T is a (possibly cv-qualified) non-POD class type (or array thereof), the object is default-initialized (8.5). If T is a const-qualified type, the underlying class type shall have a user-declared default constructor.
      • Otherwise, the object created has indeterminate value. If T is a const-qualified type, or a (possibly cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of const-qualified type, the program is ill-formed;

      现在,这就是我的 strict 解释的初始化规则。


      Now, all that was my strict interpretation of the rules of initialisation.

      实际上,我认为你可能正确地看到与 operator new 语法的定义的潜在冲突:

      Speaking practically, I think you're probably correct in seeing a potential conflict with the definition of placement operator new syntax:


      [C ++ 11:18.6.1 / 3]: 故意不执行任何其他操作。

      [C++11: 18.6.1/3]: Remarks: Intentionally performs no other action.

      下面的示例解释了 new 可以用于构造已知地址处的对象。

      An example that follows explains that placement new "can be useful for constructing an object at a known address".

      但是,它实际上并没有谈论构造一个对象的常见用法一个已知的地址,而不会影响已经存在的值,但短语不执行任何其他操作意味着您的不确定值是以前在内存中的值。

      However, it doesn't actually talk about the common use of constructing an object at a known address without mungling the values that were already there, but the phrase "performs no other action" does suggest that the intention is that your "indeterminate value" be whatever was in memory previously.

      或者,它可以简单地禁止操作符自己采取任何操作,让分配器自由。

      Alternatively, it may simply prohibit the operator itself from taking any action, leaving the allocator free to. It does seem to me that the important point the standard trying to make is that no new memory is allocated.

      无论如何,访问这个数据调用都是非常重要的。未定义的行为:

      Regardless, accessing this data invokes undefined behaviour:


      [C ++ 11:4.1 / 1]: A非函数非数组类型 T 的glvalue(3.10)可以转换为prvalue。如果 T 是不完整类型,则需要进行此转换的程序是错误的。如果glvalue引用的对象不是
      ,则类型 T 的对象不是从 T ,或如果对象未初始化,则必须进行此转换的程序具有未定义的行为。如果 T 是非类类型,则prvalue的类型是 T 的cv非限定版本。否则,prvalue的类型为 T

      [C++11: 4.1/1]: A glvalue (3.10) of a non-function, non-array type T can be converted to a prvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If the object to which the glvalue refers is not an object of type T and is not an object of a type derived from T, or if the object is uninitialized, a program that necessitates this conversion has undefined behavior. If T is a non-class type, the type of the prvalue is the cv-unqualified version of T. Otherwise, the type of the prvalue is T.

      它并不重要:您无法顺从观察原始值

      这篇关于放置新的和未初始化的POD成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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