C++标准对象生命周期:嵌套对象复用存储的示例问询
对象存储被嵌套对象复用的示例(标准反例)
没问题,咱们先把你提到的C++标准basic.life章节的原文贴出来(你标注的加粗部分我原样保留):
类型为T的对象o的生命周期结束于:若T是带有non-trivial destructor([class.dtor])的类类型,则析构函数调用开始时,或对象占用的存储被释放时,或被未嵌套于o的对象复用([intro.object])时。
这里的核心逻辑是:只有当o的存储被「不嵌套于o的对象」复用时,o的生命周期才会结束。反过来,如果复用o存储的是「嵌套于o的对象」(比如o的成员子对象、基类子对象、union成员、数组元素等),那么o的生命周期不会因此终止——这就是你要找的标准所述情况的反例。
下面给两个具体的代码示例:
示例1:Union成员复用外层对象存储
Union的所有成员共享同一块内存区域,而union的成员属于外层union对象的嵌套子对象,所以用union成员复用存储时,外层对象的生命周期不受影响:
#include <iostream> struct MyUnion { // 两个共享存储的成员,都是MyUnion的嵌套子对象 int plain_val; struct NestedObj { int nested_val; NestedObj(int val) : nested_val(val) {} } nested_obj; }; int main() { MyUnion o; // 先激活plain_val成员,使用o的存储 o.plain_val = 42; std::cout << "当前活跃成员:plain_val = " << o.plain_val << std::endl; // 销毁plain_val(平凡类型无需显式析构),复用o的存储构造嵌套子对象nested_obj new (&o.nested_obj) MyUnion::NestedObj(100); std::cout << "当前活跃成员:nested_obj.nested_val = " << o.nested_obj.nested_val << std::endl; // 此时o的生命周期仍然有效,只是活跃成员切换为nested_obj // 最后显式销毁nested_obj o.nested_obj.~NestedObj(); }
在这个例子里,MyUnion对象o的存储被它的嵌套子对象nested_obj复用,但o的生命周期并没有结束——它从创建到代码结束一直是有效的MyUnion对象。
示例2:类成员存储复用外层对象的内存
我们可以在一个类的内部开辟一块存储区域,用来动态构造/销毁它的嵌套子对象,此时复用的是外层对象的存储,但外层对象的生命周期不受影响:
#include <iostream> struct Inner { int data; Inner(int d) : data(d) { std::cout << "Inner构造,data=" << d << std::endl; } ~Inner() { std::cout << "Inner销毁,data=" << data << std::endl; } }; struct Outer { // 这块buf属于Outer对象存储的一部分,用来存放Inner子对象 alignas(Inner) char storage_buf[sizeof(Inner)]; // 获取Inner子对象的指针 Inner* get_inner() { return reinterpret_cast<Inner*>(storage_buf); } // 构造Outer时初始化Inner Outer(int init_val) { new (storage_buf) Inner(init_val); } // 重置Inner:销毁旧对象,复用buf构造新对象 void reset_inner(int new_val) { get_inner()->~Inner(); // 复用Outer对象的存储(buf是Outer的成员)构造新的嵌套子对象 new (storage_buf) Inner(new_val); } // 销毁Outer时销毁Inner ~Outer() { get_inner()->~Inner(); } }; int main() { Outer o(42); std::cout << "当前Inner数据:" << o.get_inner()->data << std::endl; o.reset_inner(100); std::cout << "重置后Inner数据:" << o.get_inner()->data << std::endl; // o的生命周期直到main结束调用析构函数才终止 }
这个例子中,Outer对象o的storage_buf成员被用来反复构造Inner子对象,复用了o的存储,但因为Inner是嵌套于o的子对象,所以o的生命周期一直持续到析构函数被调用。
内容的提问来源于stack exchange,提问作者user42768
相关产品推荐
相关产品推荐

