首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >std::launder.的目的是什么?

std::launder.的目的是什么?
EN

Stack Overflow用户
提问于 2016-09-08 12:16:02
回答 2查看 32.5K关注 0票数 308

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

本文要解决的问题是什么?我需要注意的语言变化是什么?那我们在launder什么呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-09-08 12:42:31

std::launder的名字很贴切,但前提是您知道它的用途。它执行内存清洗。

考虑一下论文中的例子:

代码语言:javascript
复制
struct X { const int n; };
union U { X x; float f; };
...

U u = {{ 1 }};

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

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

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

代码语言:javascript
复制
X *p = new (&u.x) X {2};

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

告诉我..。u.x.n将返回什么?

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

[basic.life]/8详细说明了什么情况下可以通过变量/指针/对旧对象的引用来访问新创建的对象。而拥有const成员是取消资格的因素之一。

所以..。我们怎样才能正确地谈论u.x.n呢?

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

代码语言:javascript
复制
assert(*std::launder(&u.x.n) == 2); //Will be true.

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

另一个不合格的因素是如果您更改了对象的类型。std::launder在这方面也可以提供帮助:

代码语言:javascript
复制
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));

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

票数 314
EN

Stack Overflow用户

发布于 2021-02-13 07:43:59

std::launder是一个错误的提名者。此函数执行与清洗相反的操作:它污染指向的内存,以消除编译器对指向的值可能存在的任何期望。它排除了任何基于这样的期望的编译器优化。

因此,在@NicolBolas的答案中,编译器可能假设某些内存保存了一些常量值;或者是未初始化的。你在告诉编译器:“那个地方(现在)已经被污染了,不要做这个假设”。

如果你想知道为什么编译器一开始总是坚持它天真的期望,并且需要你明显地破坏它的东西-你可能想要阅读这篇讨论:

Why introduce std::launder rather than have the compiler take care of it?

..。这就引出了我对std::launder含义的看法。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39382501

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档