std :: launder的目的是什么?
P0137引入了函数模板std::launder
并在有关联合,生命期和指针的章节中对标准进行了许多更改。
这篇论文正在解决什么问题? 我必须注意的语言有哪些变化? 我们在launder
什么?
std::launder
是恰当的命名,但只有当你知道它是什么。 它执行内存清洗 。
考虑文中的例子:
struct X { const int n; }; union U { X x; float f; }; ... U u = {{ 1 }};
该语句执行聚合初始化,用{1}
初始化U
的第一个成员。
因为n
是一个const
variables,所以编译器可以自由地假定uxn
应该总是 1。
那么,如果我们这样做会发生什么:
X *p = new (&u.x) X {2};
因为X
是微不足道的,所以在创build一个新的对象之前,我们不需要销毁旧对象,所以这是完全合法的代码。 新对象的n
成员为2。
所以告诉我…什么将返回?
显而易见的答案是2.但这是错误的,因为编译器被允许假设一个真正的const
variables(不只是一个const&
,而是一个声明为 const
的对象variables) 永远不会改变 。 但是我们只是改变了它。
[basic.life] / 8详细说明了通过variables/指针/引用访问新创build的对象的情况。 拥有一个const
成员是不合格的因素之一。
那么…我们怎么才能正确地讨论uxn
呢?
我们必须清洗我们的记忆:
assert(*std::launder(&u.xn) == 2); //Will be true.
洗钱被用来防止人们追踪你从哪里得到钱。 内存清洗是用来防止编译器追踪你的对象的来源,从而迫使它避免任何可能不再适用的优化。
另一个不合格的因素是如果你改变对象的types。 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
可以让我们launder
一下。