指向内存的指针能否用作已初始化平凡类型?平凡类型未初始化使用是否UB?
C++平凡类型生存期与未定义行为问题解析
问题清单
- 指向某块内存的指针能否被用作已初始化的平凡类型?
- 使用未初始化的平凡类型是否属于未定义行为(UB)?
代码示例
void* mem = malloc(sizeof(uint64_t)*100); void* num_mem = mem + sizeof(uint64_t)*31; //uint64_t的生存期是否从此处开始: uint64_t* mynum = reinterpret_cast<uint64_t*>(num_mem); //? *mynum = 5; //是否为UB? std::cout << *mynum << std::endl; //是否为UB? free(mem);
核心解答
1. 指针类型转换与生存期启动
reinterpret_cast<uint64_t*>(num_mem) 仅完成类型转换,不会启动uint64_t对象的生存期。此时指针只是指向一块满足对齐要求、大小足够的内存,但内存中尚未存在合法的uint64_t对象。
2. 代码中各步骤的行为判定
*mynum = 5;:不属于UB。对于uint64_t这类标量平凡类型,C++标准允许通过直接赋值操作隐式启动对象生存期——赋值操作会覆盖内存内容,同时视为对应类型的对象已被创建并初始化。std::cout << *mynum << std::endl;:不属于UB。前面的赋值已成功启动对象生存期,此时访问对象是合法的。
3. 关于placement new的必要性
对于标量平凡类型(如基础整数、浮点类型),不需要显式调用placement new,直接赋值即可隐式启动生存期。但对于自定义的平凡聚合类型(如无构造函数的struct { int x; long y; };):
- 若要直接访问成员(如
reinterpret_cast<MyStruct*>(p)->x = 1;),必须先启动生存期,此时可以通过new(p) MyStruct;(值初始化)或new(p) MyStruct{};(零初始化)完成; - 若直接对整个对象赋值(如
*reinterpret_cast<MyStruct*>(p) = {1, 2};),则赋值操作会隐式启动生存期,无需提前调用placement new。
4. 未初始化平凡类型的使用风险
使用未启动生存期的平凡类型属于UB。例如,若跳过赋值步骤直接读取*mynum,此时内存中没有合法的uint64_t对象,读取操作会触发未定义行为。
内容的提问来源于stack exchange,提问作者Arkady
相关产品推荐
相关产品推荐

