使用
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::array
的问题与使用 std::aligned_storage_t
相同:当您开始新对象的生命周期时,std::array
对象的生命周期结束。 [基础生活]p1:
类型为
T
的对象o的生命周期结束于:
- [...]
- 该对象占用的存储空间[...]被未嵌套在 o 中的对象重用。
因此很难再次访问该对象:
alignas(T) std::array<std::byte, sizeof(T)> arr;
T* ptr = std::construct_at(reinterpret_cast<T*>(arr.data()), ...);
ptr->member(); // Fine
// reinterpret_cast<T*>(arr.data())->member(); // UB: cannot call `arr.data()` since `arr` is not a `std::array`
// std::launder(reinterpret_cast<T*>(arr.data())->member(); // UB: same as above
// reinterpret_cast<T*>(&arr)->member(); // UB: &arr does not point to *ptr
std::launder(reinterpret_cast<T*>(&arr))->member(); // OK, but confusing
// Or if you can't use alignas
template<typename T>
T* align_ptr_for_one(void* source, std::size_t size) {
return reinterpret_cast<T*>(std::align(alignof(T), sizeof(T), ptr, sz));
}
std::array<std::byte, sizeof(T) + alignof(T)> arr;
T* ptr = std::construct_at(align_ptr_for_one<T>(arr.data(), arr.size()), ...);
ptr->member(); // Fine
// align_ptr_for_one<T>(arr.data(), arr.size())->member(); // UB: cannot call `arr.data()` since `arr` is not a `std::array`
// std::launder(align_ptr_for_one<T>(arr.data(), arr.size()))->member(); // UB: same as above
// align_ptr_for_one<T>(&arr, arr.size())->member(); // UB: align(&arr) does not point to *ptr
std::launder(align_ptr_for_one<T>(&arr, arr.size()))->member();
并非不可能,但只是容易出错,因为当数组的生命周期结束时,对原始
std::array
的任何引用都不再指向任何对象。