问题描述
P0137 介绍功能模板 std::launder
并在有关联合、生命周期和指针的部分对标准进行了很多很多更改.
P0137 introduces the function template std::launder
and makes many, many changes to the standard in the sections concerning unions, lifetime, and pointers.
这篇论文要解决的问题是什么?我必须注意语言的哪些变化?我们洗钱
在做什么?
What is the problem this paper is solving? What are the changes to the language that I have to be aware of? And what are we launder
ing?
推荐答案
std::launder
的命名恰如其分,但前提是您知道它的用途.它执行内存清洗.
std::launder
is aptly named, though only if you know what it's for. It performs memory laundering.
考虑论文中的例子:
struct X { const int n; };
union U { X x; float f; };
...
U u = {{ 1 }};
该语句执行聚合初始化,用 {1}
初始化 U
的第一个成员.
That statement performs aggregate initialization, initializing the first member of U
with {1}
.
因为 n
是一个 const
变量,编译器可以自由地假设 uxn
应该 总是 为 1.
Because n
is a const
variable, the compiler is free to assume that u.x.n
shall always be 1.
如果我们这样做会发生什么:
So what happens if we do this:
X *p = new (&u.x) X {2};
因为 X
是微不足道的,我们不需要在旧对象的位置上创建新对象之前销毁旧对象,所以这是完全合法的代码.新对象的 n
成员为 2.
Because X
is trivial, we need not destroy the old object before creating a new one in its place, so this is perfectly legal code. The new object will have its n
member be 2.
那么告诉我...u.x.n
会返回什么?
So tell me... what will u.x.n
return?
显而易见的答案是 2.但那是错误的,因为编译器可以假设一个真正的 const
变量(不仅仅是一个 const&
,而是一个对象变量声明 const
) 永远不会改变.但我们只是改变了它.
The obvious answer will be 2. But that's wrong, because the compiler is allowed to assume that a truly const
variable (not merely a const&
, but an object variable declared const
) will never change. But we just changed it.
[basic.life]/8 阐明了可以通过变量/指针/对旧对象的引用访问新创建的对象的情况.拥有 const
成员是取消资格的因素之一.
[basic.life]/8 spells out the circumstances when it is OK to access the newly created object through variables/pointers/references to the old one. And having a const
member is one of the disqualifying factors.
那么……我们如何正确地谈论u.x.n
?
So... how can we talk about u.x.n
properly?
我们必须清洗我们的记忆:
We have to launder our memory:
assert(*std::launder(&u.x.n) == 2); //Will be true.
洗钱用于防止人们追踪您的资金来源.内存清洗用于防止编译器跟踪您从何处获取对象,从而迫使它避免任何可能不再适用的优化.
Money laundering is used to prevent people from tracing where you got your money from. Memory laundering is used to prevent the compiler from tracing where you got your object from, thus forcing it to avoid any optimizations that may no longer apply.
另一个不合格的因素是您是否更改了对象的类型.std::launder
在这里也可以提供帮助:
Another of the disqualifying factors is if you change the type of the object. std::launder
can help here too:
aligned_storage<sizeof(int), alignof(int)>::type data;
new(&data) int;
int *p = std::launder(reinterpret_cast<int*>(&data));
[basic.life]/8 告诉我们,如果在旧对象的存储中分配新对象,则无法通过指向旧对象的指针访问新对象.launder
允许我们回避这一点.
[basic.life]/8 tells us that, if you allocate a new object in the storage of the old one, you cannot access the new object through pointers to the old. launder
allows us to side-step that.
这篇关于std::launder 的目的是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!