在已销毁对象的存储空间内使用存活对象是否安全?
结合C++对象生命周期与内存管理规则,逐步骤验证合法性:
步骤1:创建Object1
Object1的union成员o(类型Object2)不会被自动初始化,因为C++中union的非静态自定义类型成员默认不会随宿主对象一同构造,这是符合标准的行为。步骤2:用placement new构造Object2
调用new (&object1->o) Object2()是合法的:这块内存属于已分配的Object1存储空间,且此前没有构造过任何对象,placement new仅负责在指定内存区域启动Object2的生命周期,不会额外分配内存,操作合规。步骤3:析构Object1
手动调用object1->~Object1()只会执行Object1的析构逻辑——这里Object1的析构函数为空,不会对union内的Object2做任何操作,也不会终止Object2的生命周期。此时Object1的内存仍未释放,Object2的存储空间依然有效。步骤4:访问Object2
Object2的生命周期尚未结束(未调用其析构函数),且所在内存未被回收,直接访问其成员a/b/c属于合法操作,不存在未定义行为。步骤5:析构Object2
因为Object2是通过placement new手动构造的,必须手动调用其析构函数object2->~Object2()来终止生命周期,这一步是必要且合规的。步骤6:释放内存
由于已经手动调用了Object1的析构函数,使用operator delete(object1)仅负责将内存归还给系统,不会再次调用析构,避免了重复析构的风险,操作合法。
额外注意点
如果Object1的析构函数包含会覆盖union内存区域的逻辑(比如给成员d赋值时意外覆盖到union区域),那后续访问Object2就会出问题,但本示例中Object1的析构为空,不存在这个风险;另外,本示例的union仅包含一个成员,天然符合“同一时间仅一个成员活跃”的union使用规则,无需额外顾虑。
内容的提问来源于stack exchange,提问作者Peter Fletcher

