std::launder 的目的是什么?

新手上路,请多包涵

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

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

原文由 Barry 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
1 个回答

std::launder 的名字恰如其分,但前提是您知道它的用途。它执行 _内存清洗_。

考虑论文中的示例:

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

U u = {{ 1 }};

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

因为 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 也可以在这里提供帮助:

 alignas(int) char data[sizeof(int)];
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));

[basic.life]/8 告诉我们,如果在旧对象的存储中分配新对象,则无法通过指向旧对象的指针访问新对象。 launder 允许我们回避这一点。

原文由 Nicol Bolas 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题