P0137 引入了函数模板 std::launder
,并对有关 union 、生命周期和指针的部分中的标准进行了很多很多更改。
这篇论文要解决什么问题?我必须注意语言的哪些变化?我们 launder
是什么?
最佳答案
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
变量(不仅仅是一个 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
允许我们回避这一点。关于c++ - std::launder 的目的是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39382501/