std ::洗钱的目的是什么?


242

P0137引入了功能模板, std::launder并在有关并集,生存期和指针的部分中对标准进行了许多更改。

本文要解决的问题是什么?我必须了解的语言有哪些变化?那我们在做launder什么?


2
您是在询问纸张本身还是关于纸张std::launderstd::launder“用于获取指向由相同类型的现有对象占用的存储中创建的对象的指针,即使该对象具有const或引用成员也是如此”。
txtechhelp

7
关于该主题的有用链接。另外这个问题stackoverflow.com/questions/27003727/...
保罗·鲁尼

该版本现已在VC2017中的15.7.0版中发布
Damian

根据标准,指针是琐碎的类型,所以洗手不做任何事情。;)
curiousguy

Answers:


250

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变量(不仅是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让我们回避这一点。


34
那么我的tl; dr是正确的吗:“洗钱基本上是针对非UB类型的修剪”?
druckermanly

13
你能解释为什么这是真的吗?“由于nconst变量,所以编译器可以自由地假定其u.x.n始终为1。” 它在标准中的何处表示?我问,因为您指出的这个问题对我而言似乎意味着它首先是错误的。仅在“按条件”规则下才应为真,这在此处失败。我想念什么?
user541686'9

10
@Mehrdad [basic.life] / 8:“ 如果在原始对象所占的存储位置创建了一个新对象,则原始对象的名称将自动引用该新对象[...],如果:[...]的类型[...]不包含任何非静态数据成员,其类型为常量限定或引用类型[...]
ecatmur

14
@Barry Very; 如果在该地址所ptr代表的位置上没有T类型的对象,则您破坏了launder的先决条件,因此毫无意义地谈论结果。
TC

17
@NicolBolas一个人只能希望超级猫能尽力游说委员会,就像他们无休止地要求其他第三方语言用户回答SO一样。此外,一个好的优化编译器无论如何都将优化您正确的解决方案,memcpy使其成为支持(即松散对齐)平台上的就地重新解释。
underscore_d
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.