Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I overwrite a const object via placement-new?

Basic.life/8 tells us that we can use the storage occupied by an object to create a new one after its lifetime has ended and use its original name to refer to it unless:

  • the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and [...]

emphasis mine

But, just below that we can see a note saying that:

  • If these conditions are not met, a pointer to the new object can be obtained from a pointer that represents the address of its storage by calling std​::​launder

This explains the purposes of std::launder. We can have a class type that has const members and use placement-new to create a new object there with different internal values.

What surprises me is the first part of the first quote. It clearly indicates that if the storage is const (not necessarily contains const members, but the whole object is declared as const), we cannot use it to refer to a new object as is, but it may imply that std::launder may fix it.

But how would we create such object? The simplest example fails:

const auto x = 5;
new (&x) auto(10);

It's because we cannot use const void* as a buffer for placement-new. We could const_cast it, but casting away a "true" constness is Undefined Behaviour. I believe this is also the case here.

I would understand if there simply was a prohibition of using const objects as placement-new buffer, but if that would be the case, what would be the purpose of the emphasised part of the first quote? Can we use reuse a truly const object's storage for a different object?

like image 626
Fureeish Avatar asked Nov 14 '22 19:11

Fureeish


1 Answers

Apparently all it took was to look just 2 items below the part of the standard I linked to. Basic.life/10 tells us that:

Creating a new object within the storage that a const complete object with static, thread, or automatic storage duration occupies, or within the storage that such a const object used to occupy before its lifetime ended, results in undefined behavior.

And it comes with an example:

struct B {
  B();
  ~B();
};

const B b;

void h() {
  b.~B();
  new (const_cast<B*>(&b)) const B;     // undefined behavior
}

which ultimately leads me to a conclusion that it's illegal to use placement-new on a memory occupied by a truly const object. Thus, I believe that the note mentioned in the question (in reference to point 8) is faulty - it should exclude the case in question.

like image 167
Fureeish Avatar answered Mar 21 '23 05:03

Fureeish