小编典典

std::launder 的目的是什么?

all

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

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


阅读 83

收藏
2022-04-14

共1个答案

小编典典

std::launder恰当地命名,但前提是您知道它的用途。它执行 内存清洗

考虑论文中的示例:

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

U u = {{ 1 }};

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

因为n是一个const变量,编译器可以自由假设它u.x.n应该 总是 1。

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

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

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

所以告诉我......什么会u.x.n返回?

显而易见的答案是 2。但这是错误的,因为允许编译器假设一个真正的const变量(不仅仅是 a ,而是 声明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允许我们回避这一点。

2022-04-14