对栈变量使用placement new是否合法?相关操作符合C++标准吗?
问题解答
1. 能否取已经调用过析构函数的对象的地址?
可以,该操作完全符合C++标准定义,不属于未定义行为。
对象的生命周期和其占用存储的生命周期是两个独立的概念:调用析构函数只会结束当前对象的生命周期,但是栈对象对应的存储会一直保持分配状态,直到变量离开作用域、对应栈帧被回收为止。只要存储本身处于已分配状态,取这块存储的地址就是合法操作,拿到的地址也可以作为placement new的有效入参使用。
注意:标准中提到的“析构函数调用后使用原对象属于未定义行为”,特指访问原对象的成员变量、调用成员函数这类依赖对象内部状态的操作,不包含取地址的行为。
2. 对栈变量调用placement new属于正确的操作吗?
只要遵守使用规则,该操作就是合法且符合标准的,属于C++支持的常规用法。使用时需要满足以下前提:
- 调用
placement new前,必须先显式调用栈上原有对象的析构函数,释放原有对象持有的所有资源,避免资源泄漏,也防止新旧对象的内部状态产生冲突,你给出的第二段代码就是符合该要求的示例。 placement new构造的新对象类型需要和原栈变量类型兼容,且原类型不能包含const成员、引用成员,否则会触发未定义行为。- 不需要额外处理地址对齐问题:栈变量本身的内存对齐就满足对应类型的要求,天然适配
placement new的对齐要求。
按照规则操作的情况下,栈变量离开作用域时,编译器自动调用的析构函数会作用在你新构造的对象上,刚好完成资源释放,不会出现重复析构或者资源泄漏的问题。
内容的提问来源于stack exchange,提问作者dasfex
相关产品推荐
相关产品推荐

