Kri*_*ege 14 c++ initialization placement-new
C++标准是否保证未初始化的POD成员在新的位置后保留其先前的值?
或者更准确地说,根据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);
}
Run Code Online (Sandbox Code Playgroud)
C++ 03的答案是否相同?
Lig*_*ica 20
C++标准是否保证未初始化的POD成员在新的位置后保留其先前的值?
根据C++ 11,是否总能满足以下断言?
没有.
未初始化的数据成员具有不确定的值,这与说基础内存保持不变完全相同.
[C++11: 5.3.4/15]:甲新表达式创建类型的对象T如下初始化该对象:
- 如果省略new-initializer,则默认初始化对象(8.5); 如果没有执行初始化,则该对象具有不确定的值.
- 否则,根据8.5的初始化规则解释new-initializer以进行直接初始化.
[C++11: 8.5/6]:默认初始化类型对象T意味着:
- 如果
T是(可能是cv限定的)类类型(第9节),则调用默认构造函数T(如果T没有可访问的默认构造函数,则初始化是错误的);- 如果
T是数组类型,则每个元素都是默认初始化的;- 否则,不执行初始化.
[C++11: 12.1/6]:当使用odr-used(3.2)创建其类类型(1.8)的对象或在第一次声明后显式默认为默认构造函数时,默认构造函数是默认的并且未定义为已删除.隐式定义的默认构造函数执行该类的初始化集,该初始化集将由该用户编写的默认构造函数执行,该类没有ctor-initializer(12.6.2)和空复合语句.
[C++11: 12.6.2/8]:在非委托构造函数中,如果给定的非静态数据成员或基类未由mem-initializer-id指定(包括没有mem-initializer-list的情况,因为构造函数没有ctor-initializer)然后,实体不是抽象类(10.4)的虚基类
- 如果实体是具有大括号或等于初始值的非静态数据成员,则按照8.5中的规定初始化该实体;
- 否则,如果实体是变体成员(9.5),则不执行初始化;
- 否则,实体默认初始化(8.5).
(注意:第一个选择12.6.2/8是如何beta处理您的会员)
[C++11: 8.5/6]:默认初始化类型对象T意味着:
- 如果
T是(可能是cv限定的)类类型(第9节),T则调用默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);- 如果
T是数组类型,则每个元素都是默认初始化的;- 否则,不执行初始化.
[C++11: 8.5/11]:如果没有为对象指定初始化程序,则默认初始化该对象; 如果未执行初始化,则具有自动或动态存储持续时间的对象具有不确定的值.
编译器可以选择在分配期间将底层内存清零(或以其他方式更改).例如,已知调试模式下的Visual Studio会将可识别的值0xDEADBEEF写入内存以帮助调试; 在这种情况下,您可能会看到0xCDCDCDCD它们用来表示"清洁记忆"(参考).
请问它,在这种情况下?我不知道.我不认为我们可以知道.
我们所知道的是C++并没有禁止它,我相信这会让我们得出这个答案的结论.:)
C++ 03的答案是否相同?
是的,虽然逻辑略有不同:
[C++03: 5.3.4/15]:甲新表达式创建类型的对象T如下初始化该对象:
- 如果省略new-initializer:
- 如果
T是(可能是cv限定的)非POD类类型(或其数组),则对象是默认初始化的(8.5).如果T是const限定类型,则基础类类型应具有用户声明的默认构造函数.- 否则,创建的对象具有不确定的值.如果
T是const限定类型,或者(可能是cv限定的)POD类类型(或其数组)包含(直接或间接)const限定类型的成员,则该程序是不正确的;- 如果new-initializer属于表单
(),则该项是值初始化的(8.5);- 如果new-initializer是表单类型
(expression-list)并且T是类类型,则使用expression-list参数(8.5)调用相应的构造函数;- 如果新初始化的形式的
(expression-list)和T是一个算术,枚举,指针或指针到构件类型和expression-list包含正好一个表达,那么该对象被初始化为表达式(8.5)的(可能转换的)值;- 否则new-expression是不正确的.
现在,所有这些都是我对初始化规则的严格解释.
说实话,我认为你可能正确看到与放置operator new语法定义的潜在冲突:
[C++11: 18.6.1/3]:备注:故意不执行任何其他操作.
下面的示例解释了放置new"对于在已知地址处构造对象可能是有用的".
但是,它实际上并没有谈到在一个已知地址构建一个对象的常见用法,而没有混淆已经存在的值,但短语"不执行其他操作"确实表明意图是你的"不确定值"是以前记忆中的任何东西.
或者,它可能只是禁止操作员自己采取任何行动,让分配器自由.它确实在我看来,标准的努力使重要的一点是,任何新的内存分配.
无论如何,访问此数据会调用未定义的行为:
[C++11: 4.1/1]:T可以将非函数非数组类型的glvalue(3.10)转换为prvalue.如果T是不完整类型,则需要进行此转换的程序格式不正确.如果glvalue引用的对象不是类型的对象,T并且不是派生类型的对象T,或者如果对象未初始化,则需要此转换的程序具有未定义的行为.如果T是非类类型,则prvalue的类型是cv-nonqualified versionT.否则,prvalue的类型是T.
所以它并不重要:无论如何你无法顺从地观察原始值.
C++11 12.6.2/8“初始化基数和成员”说:
在非委托构造函数中,如果给定的非静态数据成员或基类不是由 mem-initializer-id 指定的(包括由于构造函数没有 ctor-initializer 而没有 mem-initializer-list 的情况)并且实体不是抽象类的虚拟基类(10.4),那么
- 如果该实体是具有大括号或等于初始化器的非静态数据成员,则该实体按照 8.5 中的规定进行初始化;
- 否则,如果实体是变体成员(9.5),则不执行初始化;
- 否则,该实体将被默认初始化(8.5)。
默认初始化int不执行任何操作(8.5/6“初始化程序”):
默认初始化 T 类型的对象意味着:
- 如果 T 是一个(可能是 cv 限定的)类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是格式错误的);
- 如果 T 是数组类型,则每个元素都默认初始化;
- 否则,不执行初始化。
所以该成员alpha应该独自一人。
| 归档时间: |
|
| 查看次数: |
1151 次 |
| 最近记录: |