std::construct_at是否启动对象生命周期?相关代码是否存在UB?
关于std::construct_at启动对象生命周期的分析
核心结论
std::construct_at会启动指定存储位置的对象生命周期,你代码中使用std::construct_at的版本不存在未定义行为,和注释里的定位new表达式效果完全一致。
标准依据与分析
- std::construct_at的本质
根据C++标准定义,std::construct_at的效果等价于:
return ::new (voidify(*location)) T(std::forward
(args)...);
这本质就是定位new表达式,而标准明确规定:对象通过定义、new表达式、隐式对象创建操作等方式创建。因此,定位new表达式属于合法的对象创建手段,会在指定的存储位置启动对象的生命周期。
std::array子对象的生命周期问题
你提到的隐式创建std::array对象时不会启动其非隐式生命周期的T子对象,这一点是正确的。但std::construct_at是显式的对象创建操作,它会直接在Array->data()指向的每个内存位置,分别创建(启动)T类型对象的生命周期,完全覆盖了隐式创建的局限性,不存在未定义行为。cppreference示例的疑惑澄清
cppreference上的std::construct_at示例使用std::bit_cast是特定场景的需求(比如从无对象的原始存储直接转换类型),和你的场景无关。你的代码是通过显式构造操作在已分配的存储上创建对象,不需要依赖bit_cast来启动生命周期。
代码回顾
你提供的实现代码:
// 创建std::byte存储以利用“隐式对象创建”特性 alignas(alignof(T)) std::byte storage[sizeof(std::array<T, N>)]; std::array<T, N>* const Array = std::launder(reinterpret_cast<std::array<T, N>*>(storage)); // 初始化存储中的对象 T* it = Array->data(); // 通过std::construct_at在存储中构造对象 for (std::size_t i = 0; i != N; ++i) { std::construct_at(it, gen(static_cast<int>(i))); // 非UB // new (it) T(gen(static_cast<int>(i))); // 同样非UB ++it; }
这段代码中,std::construct_at和定位new表达式都能合法启动T子对象的生命周期,两者的行为在标准层面是等价的。
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

