求解释C++标准3.8 Object lifetime相关未定义行为的示例
C++标准3.8对象生存期条款示例解释
在对象生存期开始前但已分配其将占用的存储时,或对象生存期结束后且其占用的存储未被重用或释放时,指向该对象将要或曾经所在存储位置的指针可被使用,但仅能以有限方式使用。对于处于构造或销毁中的对象,参见12.7条款。除此之外,此类指针指向已分配的存储(3.7.4.2),将其当作void*类型指针使用是良定义的。允许通过此类指针进行间接访问,但得到的左值仅能以如下所述的有限方式使用。若出现以下情况,程序将产生undefined behavior:
使用该指针访问对象的非静态数据成员或调用对象的非静态成员函数,
以下是针对该条款的具体示例:
一、对象生存期开始前的场景
通过malloc分配存储但未构造对象时,指针指向的是已分配但无有效对象的内存区域。
合法操作示例
#include <cstdlib> struct MyObj { int val; void func() {} }; int main() { // 分配MyObj大小的存储,但对象未构造(生存期未启动) MyObj* ptr = static_cast<MyObj*>(std::malloc(sizeof(MyObj))); // 合法:转换为void*类型使用 void* void_ptr = ptr; // 合法:获取指针自身的地址(未访问对象成员) MyObj** ptr_addr = &ptr; // 合法:指针比较操作 if (ptr != nullptr) { // 执行非成员访问的逻辑 } // 构造对象,启动生存期 new (ptr) MyObj{42}; // 使用对象后销毁并释放存储 ptr->~MyObj(); std::free(ptr); return 0; }
未定义行为(UB)示例
#include <cstdlib> struct MyObj { int val; void func() {} }; int main() { MyObj* ptr = static_cast<MyObj*>(std::malloc(sizeof(MyObj))); // UB:访问未构造对象的非静态数据成员 int x = ptr->val; // UB:调用未构造对象的非静态成员函数 ptr->func(); std::free(ptr); return 0; }
二、对象生存期结束后的场景
对象已调用析构函数销毁,但存储未被释放或重用时,指针仍指向原内存区域。
合法操作示例
#include <cstdlib> struct MyObj { int val; void func() {} }; int main() { MyObj* ptr = new MyObj{42}; // 销毁对象,生存期结束,但存储未释放 ptr->~MyObj(); // 合法:转换为void*类型使用 void* void_ptr = ptr; // 合法:指针比较操作 if (ptr != nullptr) { // 执行非成员访问的逻辑 } // 合法:在原存储位置重新构造对象 new (ptr) MyObj{100}; // 再次销毁并释放存储 ptr->~MyObj(); delete ptr; return 0; }
未定义行为(UB)示例
#include <cstdlib> struct MyObj { int val; void func() {} }; int main() { MyObj* ptr = new MyObj{42}; // 销毁对象,生存期结束 ptr->~MyObj(); // UB:访问已销毁对象的非静态数据成员 int x = ptr->val; // UB:调用已销毁对象的非静态成员函数 ptr->func(); delete ptr; return 0; }
关键说明
当对象生存期未开始或已结束时,指针仅能用于与存储本身相关的操作(如转换为void*、指针比较、重新构造对象等)。一旦尝试访问对象的非静态成员(数据或函数),就会触发未定义行为——程序可能出现垃圾值、崩溃,或被编译器进行不可预期的优化。
内容的提问来源于stack exchange,提问作者getsoubl
相关产品推荐
相关产品推荐

