使用 std::array 作为存储会调用 UB 吗?

blo*_*d04 5 c++ lifetime placement-new language-lawyer c++20

std::array<std::byte, N> storage分配一些内存可以用作存储吗?例如,a.data()即使分配对象的生命周期与 无关,在 上调用placement-new 是否安全std::array

std::aligned_storage_t在 C++23 中被弃用的原因是,它的 UB 植根于其设计(并且 API 很差,但在这个问题中并非如此),虽然它非常接近 的用例std::array,所以是否强制使用C 风格的数组std::byte storage[N]作为内存分配的存储,不是std::array(甚至可能std::vector)。

Art*_*yer 4

问题std::aligned_storage_t是,当您开始新对象的生命周期时,该std::aligned_storage_t对象的生命周期就结束了。[基本生活]p1

\n
\n

o类型的对象的生命周期T在以下情况结束:

\n
    \n
  • [...]
  • \n
  • he 对象占用的存储空间 [...] 被未嵌套在o中的对象重用。
  • \n
\n
\n

因此,如果您要使用std::arrayas ,就好像它是一样std::aligned_storage_t,您将无法调用数组的任何成员函数,因为数组的生命周期将结束:

\n
alignas(T) std::array<std::byte, sizeof(T)> arr;\nT* ptr = std::construct_at(reinterpret_cast<T*>(&arr), ...);\n// Lifetime of `arr` ends\n// arr.data();  // UB: lifetime of `std::array` has ended\n
Run Code Online (Sandbox Code Playgroud)\n

但是,由于您使用.data()的指针std::array,因此生命周期不会结束,因为该成员std::byte[N]将为新对象[intro.object]p3提供存储:

\n
\n

如果在与 N \xe2\x80\x9d 类型的 \xe2\x80\x9carray 或 Nunsigned char \xe2\x80\x9d 类型的 \xe2\x80\x9carray 的另一个对象 e 关联的存储中创建完整的对象,则该数组提供存储对于创建的对象如果 [...] std\xe2\x80\x8b::\xe2\x80\x8bbyte

\n
\n

并通过[intro.object]p4

\n
\n

如果满足以下条件,则对象a嵌套另一个对象b中:

\n
    \n
  • a是b的子对象,或者
  • \n
  • b为a提供存储,或
  • \n
  • 存在一个对象c,其中a嵌套在c中,而c嵌套在b中。
  • \n
\n
\n

因此,用bstd::byte[N] =的成员arrc = 新构造的对象实例化第二个选项,用c = 成员std::byte[N]a = 新构造的对象和b =std::array<std::byte, N>对象实例化第三个选项。新构造的对象嵌套在std::array.

\n

因此它可以像使用对象一样使用std::byte[N]std::array<std::byte, N>即为嵌套在 array/ 中的新对象提供存储std::array):

\n
alignas(T) std::array<std::byte, sizeof(T)> arr;\nT* ptr = std::construct_at(reinterpret_cast<T*>(arr.data()), ...);\n// Lifetime of `arr` continues: The array provides storage for the `T` object.\nfor (std::byte repr : arr) {\n    // bytes of the object representation of `*ptr`\n}\nT* ptr2 = std::launder(reinterpret_cast<T*>(arr.data());  // Points to the same object as `*ptr`\n
Run Code Online (Sandbox Code Playgroud)\n

  • @MooingDuck 可以通过联合很好地实现:https://godbolt.org/z/5Txzn5q54 (3认同)