给定一个类,其中唯一的成员是char[10]
,没有继承,也没有虚拟成员,它有一个构造函数,不会以任何方式提及数组(这样它就会得到默认初始化 - >没有初始化,如下:
class in_place_string {
char data[10];
static struct pre_initialized_type {} pre_initialized;
in_place_string(pre_initialized_type) {} //This is the constructor in question
in_place_string() :data() {} //this is so you don't yell at me, not relevent
};
是否定义了将此类放置到已有数据的缓冲区中的行为,然后从数组成员中读取?
int main() {
char buffer[sizeof(in_place_string)] = "HI!";
in_place_string* str = new(buffer) in_place_string(in_place_string::pre_initialized);
cout << str->data; //undefined behavior?
}
我很确定它没有明确定义,所以我要问这是实现定义还是未定义的行为。
答案 0 :(得分:4)
您没有执行reinterpret_cast
(这不安全,因为该类具有非平凡的初始化);您正在创建一个其成员未初始化的新对象。
对未初始化的对象执行lvalue-&gt; rvalue转换会给出不确定的值和未定义的行为。那对象是未初始化的吗?
根据5.3.4 new-expression 创建的所有对象具有动态存储持续时间。放置新品也不例外。
由new-expression创建的实体具有动态存储持续时间
然后8.5说
如果没有为对象指定初始值设定项,则默认初始化该对象。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,并且如果没有对该对象执行初始化,则该对象保留不确定的值,直到该值被替换(5.17)。 [注意:具有静态或线程存储持续时间的对象是零初始化的,请参阅结束注释]如果评估产生不确定的值,则行为是未定义的,除非在以下情况下:
并且以下情况仅允许unsigned char
,即使这样,该值也无用。
在您的情况下,新对象具有动态存储持续时间(!),并且未执行初始化的成员具有不确定的值。阅读它们会产生不确定的行为。
答案 1 :(得分:1)
我认为相关条款是8.5 [dcl.init]第12段:
如果没有为对象指定初始值设定项,则默认初始化该对象。当获得具有自动或动态存储持续时间的对象的存储时,该对象具有不确定的值,并且如果没有对该对象执行初始化,则该对象保留不确定的值,直到该值被替换(5.17)。 [注意:具有静态或线程存储持续时间的对象是零初始化的,请参见3.6.2。 -end note]如果评估产生不确定的值,则行为是未定义的,除了在 以下情况:
- 如果通过以下评估产生无符号窄字符类型(3.9.1)的不确定值:
- 条件表达式的第二个或第三个操作数(5.16),
- 逗号表达式(5.18)的右操作数,
- 转换或转换为无符号窄字符类型(4.7,5.2.3,5.2.9,5.4)或
的操作数- 废弃值表达式(第5条),然后操作的结果是不确定的值。
- 如果通过评估一个简单赋值运算符(5.17)的右操作数产生无符号窄字符类型的不确定值,该操作数的第一个操作数是无符号窄字符类型的左值,则不确定值将替换该对象的值由左操作数引用。
- 如果在初始化无符号窄字符类型的对象时通过初始化表达式的求值产生无符号窄字符类型的不确定值,则该对象被初始化为不确定的值。
我不认为任何例外情况适用。由于在构造对象之后初始化之前读取了值,因此我认为代码会导致未定义的行为。