为什么引入`std :: launder`而不是让编译器来处理呢? [英] Why introduce `std::launder` rather than have the compiler take care of it?

查看:101
本文介绍了为什么引入`std :: launder`而不是让编译器来处理呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚阅读

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

坦白说,我被抓挠了头.

and frankly, I am left scratching my head.

让我们从@NicolBolas接受的答案中的第二个示例开始:

Let's start with the second example in @NicolBolas' accepted answer:

aligned_storage<sizeof(int), alignof(int)>::type data; 
new(&data) int; 
int *p = std::launder(reinterpret_cast<int*>(&data)); 

[basic.life]/8告诉我们,如果您在存储旧对象,您将无法通过访问新对象指向旧的指针. std :: 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. std::launder allows us to side-step that.

那么,为什么不只是更改语言标准,以使通过 reinterpret_cast< int *>(& data)访问 data 是有效/适当的呢?在现实生活中,洗钱是一种将现实隐藏在法律面前的方法.但是我们没有什么可隐藏的-我们在这里做的事情完全合法.那么,当编译器注意到我们正在以这种方式访问​​ data 时,为什么不能将其行为更改为 std :: launder()行为呢?

So, why not just change the language standard so that accessing data through a reinterpret_cast<int*>(&data) is valid/appropriate? In real life, money laundering is a way to hide reality from the law. But we don't have anything to hide - we're doing something perfectly legitimate here. So why can't the compiler just change it's behavior to its std::launder() behavior when it notices we're accessing data this way?

第一个示例:

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.

那么为什么当我们编写此类代码并通过指针访问常量字段时,为什么不让编译器 not 做出假设呢?

So why not make the compiler not be allowed to make the assumption when we write this kind of code, accessing the constant field through the pointer?

为什么要使用这种伪函数在形式语言语义学上打一个洞,而不是根据代码是否像这些示例中的那样将语义设置为所需的语义,这才是合理的?

Why is it reasonable to have this pseudo-function for punching a hole in formal language semantics, rather than setting the semantics to what they need to be depending on whether or not the code does something like in these examples?

推荐答案

取决于代码是否执行这些示例中的操作

depending on whether or not the code does something like in these examples

因为编译器无法始终何时"以这种方式访问​​ data .

Because the compiler cannot always know when data is being accessed "this way".

就目前的情况而言,对于以下代码,允许编译器假定:

As things currently stand, the compiler is allowed to assume that, for the following code:

struct foo{ int const x; };

void some_func(foo*);

int bar() {
    foo f { 123 };
    some_func(&f);
    return f.x;
}

bar 将始终返回123.编译器可以生成实际访问该对象的代码.但是对象模型对此不是 require . f.x 是一个 const 对象(不是 const 的引用/指针),因此无法更改.而且必须始终使用 f 来命名同一对象(实际上,这是您必须更改的标准部分).因此, f.x 的值不能通过任何非UB方式更改.

bar will always return 123. The compiler may generate code that actually accesses the object. But the object model does not require this. f.x is a const object (not a reference/pointer to const), and therefore it cannot be changed. And f is required to always name the same object (indeed, these are the parts of the standard you would have to change). Therefore, the value of f.x cannot be changed by any non-UB means.

为什么要使用这种伪函数在形式语言语义学上打个洞?

Why is it reasonable to have this pseudo-function for punching a hole in formal language semantics

这是实际讨论的.该论文提出了这些问题存在了多长时间(即:自C ++ 03起),并且经常采用这种对象模型实现的优化.

This was actually discussed. That paper brings up how long these issues have existed (ie: since C++03) and often optimizations made possible by this object model have been employed.

该提案被拒绝,理由是它实际上无法解决问题.来自此行报告:

The proposal was rejected on the grounds that it would not actually fix the problem. From this trip report:

但是,在讨论过程中发现,所提议的替代方案无法处理所有受影响的方案(尤其是vtable指针在起作用的方案),并且未取得共识.

However, during discussion it came to light that the proposed alternative would not handle all affected scenarios (particularly scenarios where vtable pointers are in play), and it did not gain consensus.

该报告未对此事进行任何详细说明,有关讨论也未公开.但是该建议本身确实指出,不允许对 second 虚拟函数调用进行虚拟化,因为第一次调用可能已建立了一个新对象.因此,即使P0532也不会使洗钱变得不必要,而不必要.

The report doesn't go into any particular detail on the matter, and the discussions in question are not publicly available. But the proposal itself does point out that it wouldn't allow devirtualizing a second virtual function call, as the first call may have build a new object. So even P0532 would not make launder unnecessary, merely less necessary.

这篇关于为什么引入`std :: launder`而不是让编译器来处理呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆