P0137 引入了函数模板 std::launder,并对有关 union 、生命周期和指针的部分中的标准进行了很多很多更改。

这篇论文要解决什么问题?我必须注意语言的哪些变化?我们 launder 是什么?

最佳答案

std::launder 被恰本地命名,但前提是您知道它的用途。它执行内存清洗。
考虑论文中的例子:

struct X { const int n; };
union U { X x; float f; };
...

U u = {{ 1 }};
该语句执行聚合初始化,使用 U 初始化 {1} 的第一个成员。
因为 n 是一个 const 变量,编译器可以自由地假设 u.x.n 始终为 1。
那么如果我们这样做会发生什么:
X *p = new (&u.x) X {2};
因为 X 是微不足道的,我们不需要在旧对象的位置创建新对象之前销毁旧对象,所以这是完全合法的代码。新对象的 n 成员为 2。
那么告诉我... u.x.n 会返回什么?
显而易见的答案是 2。但这是错误的,因为编译器可以假设一个真正的 const 变量(不仅仅是一个 const& ,而是一个声明为 const 的对象变量)永远不会改变。但我们只是改变了它。
[basic.life]/8 阐明了可以通过变量/指针/对旧对象的引用访问新创建的对象的情况。并且拥有 const 成员是取消资格的因素之一。
那么......我们如何正确谈论u.x.n
我们必须清洗我们的内存:
assert(*std::launder(&u.x.n) == 2); //Will be true.
洗钱用于防止人们追踪您的资金来源。内存清洗用于防止编译器跟踪您从何处获取对象,从而迫使它避免任何可能不再适用的优化。
另一个不合格的因素是您是否更改了对象的类型。 std::launder 也可以在这里提供帮助:
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life]/8 告诉我们,如果你在旧对象的存储中分配了一个新对象,你将无法通过指向旧对象的指针访问新对象。 launder 允许我们回避这一点。

关于c++ - std::launder 的目的是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39382501/

10-13 00:06