std :: launder的目的是什么?

P0137引入了函数模板std::launder并在有关联合,生命期和指针的章节中对标准进行了许多更改。

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

std::launder是恰当的命名,但只有当你知道它是什么。 它执行内存清洗

考虑文中的例子:

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

该语句执行聚合初始化,用{1}初始化U的第一个成员。

因为n是一个constvariables,所以编译器可以自由地假定uxn应该总是 1。

那么,如果我们这样做会发生什么:

 X *p = new (&u.x) X {2}; 

因为X是微不足道的,所以在创build一个新的对象之前,我们不需要销毁旧对象,所以这是完全合法的代码。 新对象的n成员为2。

所以告诉我…什么将返回?

显而易见的答案是2.但这是错误的,因为编译器被允许假设一个真正的constvariables(不只是一个const& ,而是一个声明为 const的对象variables) 永远不会改变 。 但是我们只是改变了它。

[basic.life] / 8详细说明了通过variables/指针/引用访问新创build的对象的情况。 拥有一个const成员是不合格的因素之一。

那么…我们怎么才能正确地讨论uxn呢?

我们必须清洗我们的记忆:

 assert(*std::launder(&u.xn) == 2); //Will be true. 

洗钱被用来防止人们追踪你从哪里得到钱。 内存清洗是用来防止编译器追踪你的对象的来源,从而迫使它避免任何可能不再适用的优化。

另一个不合格的因素是如果你改变对象的types。 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可以让我们launder一下。