Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why introduce `std::launder` rather than have the compiler take care of it?

I've just read

What is the purpose of std::launder?

and frankly, I am left scratching my head.

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 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.

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?

On to the first example:

X *p = new (&u.x) X {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.

So tell me... what will u.x.n return?

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.

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?

like image 727
einpoklum Avatar asked Feb 12 '21 17:02

einpoklum


People also ask

Why is STD launder needed?

std::launder is used to "obtain a pointer to an object created in storage occupied by an existing object of the same type, even if it has const or reference members."

What does std :: launder do?

Typical uses of std::launder include: Obtaining a pointer to an object created in the storage of an existing object of the same type, where pointers to the old object cannot be reused (for instance, because either object is a base class subobject);


Video Answer


1 Answers

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

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 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

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:

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.

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.

like image 132
Nicol Bolas Avatar answered Oct 16 '22 16:10

Nicol Bolas