Hol*_*Cat 19 c++ language-lawyer c++23
灵感来源:为什么 std::aligned_storage 在 C++23 中被弃用以及使用什么替代?
\n链接的提案P1413R3(不赞成使用std::aligned_storage)表示:
\n\n使用
\naligned_*调用未定义的行为(类型无法提供存储。)
这是指[intro.object]/3:
\n\n如果在与N \xe2\x80\x9d 类型的 \xe2\x80\x9carray或N \xe2 \ 类型 \xe2\x80\x9carray 的另一个对象e关联的存储中创建了完整对象 ([expr.new]) x80\x9d ([cstddef.syn]),该数组为创建的对象提供存储,如果: ...
\nunsigned charstd\xe2\x80\x8b::\xe2\x80\x8bbyte
然后,该标准在一些定义中继续使用术语“提供存储”,但我没有看到它在任何地方说使用不同类型作为新放置的存储(无法“提供存储”)会导致 UB 。
\n那么,问题是:std::aligned_storage当用于放置新时,是什么导致了UB?
Hol*_*Cat 11
该论文在这一点上似乎是错误的。
\n如果 std::aligned_storage_t未能“提供存储”,那么它的大多数使用都会间接导致UB(见下文)。
但是否std::aligned_storage_t真的能够“提供存储”似乎还没有明确。使用带有成员的结构alignas(Y) unsigned char arr[X];(似乎)的常见实现确实根据以下内容“提供存储”[intro.object]/3,即使您将整个结构的地址传递到placement-new,而不是数组。尽管现在尚未强制执行此特定实施,但我相信强制执行它将是一个简单的非破坏性更改。
如果std::aligned_storage_t实际上没有“提供存储”,那么大多数用例都会导致 UB:
将 new 放置到无法“提供存储”的对象中本身是合法的,但是......
\n这将结束未能“提供存储”( ) 的对象的生命周期aligned_storage_t,并递归地结束所有封闭对象的生命周期。下次您访问其中任何一个时,您将获得 UB。
即使aligned_storage_t没有嵌套在其他对象中(这种情况很少见),在销毁它时也必须小心,因为调用它的析构函数也会导致 UB,因为它的生命周期已经结束。
\n\n\n...类型 T 的对象 o 的生命周期在以下情况结束:
\n\xe2\x80\x94 对象占用的存储空间...被未嵌套在[对象]内的对象重用
\n
\n\n\n如果满足以下条件,则对象 a 嵌套在另一个对象 b 中:
\n\xe2\x80\x94a 是 b 的子对象,或者
\n\xe2\x80\x94 b 为 a 提供存储,或者
\n\xe2\x80\x94 存在一个对象 c,其中 a 嵌套在 c 中,c 嵌套在 b 中。
\n
C++ 标准允许一组非常有限的类型作为其他对象的存储。可以用作其他对象存储的类型集本身不能将对齐方式打包到其类型中。
想象:
template<std::size_t N>
using bytes=std::byte[N];
template<std::size_t S, std::size_t A>
struct alignas(A) aligned{
bytes<S> data;
};
Run Code Online (Sandbox Code Playgroud)
您不能用来&aligned<12,4>安全地存储另一个对象。您不能使用此属性创建一个与其对齐的 typedef。
您可以使用aligned<12,4> a; &a.dataor 类似的,但这在语法上是不同的。
现在,该标准可以通过添加措辞来绕过它;但是对齐存储的现有定义没有这种神奇的措辞,并且在没有这种aligned_storage_t措辞的情况下,C++ 中的任何构造都不能具有用户期望的属性。我的意思是,UB 就是 UB,所以编译器可以自由地解释你的程序,就好像它是使用具有该措辞的语言编写的程序一样......但这就像用核弹打击标准错误一样。
| 归档时间: |
|
| 查看次数: |
1563 次 |
| 最近记录: |