使用
std::array<std::byte, N> storage
作为存储来分配一些内存可以吗?
例如,即使分配对象的生命周期与 a.data()
无关,在 std::array
上调用placement-new 是否安全?
std::aligned_storage_t
在 C++23 中被弃用,原因是它的 UB 植根于其设计(API 很差,但在这个问题中并非如此),而它与 的用例非常接近std::array
,所以必须使用 C 风格的数组 std::byte storage[N]
作为内存分配的存储,而不是 std::array
(甚至可能是 std::vector
)。
std::aligned_storage_t
的问题是,当您开始新对象的生命周期时,std::aligned_storage_t
对象的生命周期就结束了。 [基础生活]p1:
类型为
T
的对象o的生命周期结束于:
- [...]
- 该对象占用的存储空间[...]被未嵌套在 o 中的对象重用。
因此,如果您像使用
std::array
一样使用 std::aligned_storage_t
,您将无法调用数组的任何成员函数,因为数组的生命周期将结束:
alignas(T) std::array<std::byte, sizeof(T)> arr;
T* ptr = std::construct_at(reinterpret_cast<T*>(&arr), ...);
// Lifetime of `arr` ends
// arr.data(); // UB: lifetime of `std::array` has ended
但是,由于您使用
.data()
的std::array
指针,那么生命周期不会结束,因为成员std::byte[N]
将为新对象提供存储[intro.object]p3:
如果在与“array of N
”类型或“array of Nunsigned char
”类型的另一个对象 e 关联的存储中创建了一个完整的对象,则该 array 为创建的对象提供存储 if [. ..]std::byte
一个对象 a 嵌套在 另一个对象 b 中,如果:
- a 是 b 的子对象,或者
- b 为 a 或
提供存储空间- 存在一个对象 c,其中 a 嵌套在 c 中,c 嵌套在 b 中。
因此,用 b =
std::byte[N]
的成员 arr
和 c = 新构造的对象实例化第二个选项,用 c = 成员 std::byte[N]
和 a = 实例化第三个选项新构造的对象和 b = std::array<std::byte, N>
对象。新构造的对象嵌套在 std::array
中。
因此它的使用方式与对象是
std::byte[N]
而不是 std::array<std::byte, N>
的方式相同(即为嵌套在数组中的新对象提供存储/std::array
):
alignas(T) std::array<std::byte, sizeof(T)> arr;
T* ptr = std::construct_at(reinterpret_cast<T*>(arr.data()), ...);
// Lifetime of `arr` continues: The array provides storage for the `T` object.
for (std::byte repr : arr) {
// bytes of the object representation of `*ptr`
}
T* ptr2 = std::launder(reinterpret_cast<T*>(arr.data()); // Points to the same object as `*ptr`