C++中placement new存储复用合法性判定:哪些对象创建合法?
C++存储复用与对象生命周期问题
C++标准的多处条款提及了存储复用(storage reuse),例如对象生命周期相关的规则。但我们常难以明确区分存储复用与非法对象创建的边界,以下通过代码示例分析具体场景:
#include <cstddef> #include <cstdint> #include <new> int main() { std::byte storage[10000]; std::int32_t *po0 = new (storage + 2 * sizeof(std::int32_t)) std::int32_t; // 是否复用了po0的存储? std::int16_t *po1 = new (storage + 2 * sizeof(std::int32_t)) std::int16_t; // std::int64_t *po2 = new (storage + 2 * sizeof(std::int32_t)) std::int64_t; // std::int16_t *po3 = // new (storage + 2 * sizeof(std::int32_t) + sizeof(std::int8_t)) // std::int16_t; // std::int32_t *po4 = // new (storage + 2 * sizeof(std::int32_t) + sizeof(std::int32_t)) // std::int32_t; // std::int32_t *po5 = // new (storage + 2 * sizeof(std::int32_t) - sizeof(std::int16_t)) // std::int32_t; // std::int64_t *po6 = // new (storage + 2 * sizeof(std::int32_t) - sizeof(std::int16_t)) // std::int64_t; }
前提说明
- 为简化问题,未考虑对齐问题,仅关注新对象的创建位置(原对象之前、相同位置、内部)及与原对象的重叠情况。
- 示例使用整数类型,但可替换为任意类型。
- 假设仅创建po1至po6中的一个对象。
问题
通过placement new创建的这6个对象中,哪些是合法的、属于存储复用且会终止*po0的生命周期?
场景图示
| po0 | po0 | po0 | po0 | ||||||
|---|---|---|---|---|---|---|---|---|---|
| po1 | po1 | ||||||||
| po2 | po2 | po2 | po2 | po2 | po2 | po2 | po2 | ||
| po3 | po3 | ||||||||
| po4 | po4 | po4 | po4 | ||||||
| po5 | po5 | po5 | po5 | ||||||
| po6 | po6 | po6 | po6 | po6 | po6 | po6 | po6 | po6 | po6 |
分析结论
以下基于C++对象生命周期与存储复用的规则分析每个对象:
- po1:合法,属于存储复用,会终止
*po0的生命周期。新对象起始地址与po0完全相同,存储范围覆盖po0的前半部分,复用了po0的部分存储区域,触发原对象生命周期终止。 - po2:合法,属于存储复用,会终止
*po0的生命周期。新对象起始地址与po0相同,存储范围完全包含po0的全部存储,完全复用原对象的存储区域,直接终止其生命周期。 - po3:合法,属于存储复用,会终止
*po0的生命周期。新对象的存储完全位于po0的存储范围内,与原对象部分重叠,复用了po0的中间存储区域,导致原对象生命周期终止。 - po4:合法,但不属于存储复用,不会终止
*po0的生命周期。新对象的存储与po0的存储完全不重叠,未复用原对象的任何存储区域,po0的生命周期不受影响。 - po5:合法,属于存储复用,会终止
*po0的生命周期。新对象的起始地址在po0之前,存储范围与po0的前半部分重叠,复用了po0的部分存储区域,触发原对象生命周期终止。 - po6:合法,属于存储复用,会终止
*po0的生命周期。新对象的起始地址在po0之前,存储范围完全包含po0的全部存储,复用了原对象的存储区域,终止其生命周期。
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

