3

In C++ can you reuse the memory of an object by destroying this and then recreating another object of the same type at this? Would it work or would it be UB?

In the following example we seemingly modify a const member variable (live demo).

#include <new>


class Weird {
public:
    Weird(int x) : x(x) {}

    void operator=(int newX) {
        this->~Weird();
        new(this) Weird(newX);
    }

    operator int() const {
        return x;
    }

private:
    const int x;
};


int main() {
    Weird w = 1;
    w = 2;
    return w;
}
Dr. Gut
  • 2,053
  • 7
  • 26

1 Answers1

1

Would it work or would it be UB?

It will work and has defined behavior since C++20. Doing it with a const member variable isn't allowed in prior versions.

after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object will be or was located may be used but only in limited ways.

C++20 standard [basic.life/6]

this is such a pointer.

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if the original object is transparently replaceable by the new object.

C++20 standard [basic.life/8]

Weird is transparently replaceable by Weird.

Dr. Gut
  • 2,053
  • 7
  • 26
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • 1
    There's also https://eel.is/c++draft/basic.life#8.4, that says this doesn't work for base classes and `[[no_unique_address]]` data members. – HolyBlackCat May 30 '23 at 20:53
  • @HolyBlackCat Yes, there are a lot of conditions that needs to be fulfilled and OPs code fullfills them all as far as I can see. – Ted Lyngmo May 30 '23 at 20:56
  • Related question: Is this still legal/well-defined if you delete the line `this->~Weird();`? – Matt May 30 '23 at 20:57
  • @Matt Good question. I've seen it both with and without explicitly calling the destructor. I'm not 100% about the answer. Perhaps it's safest to always do it even if not needed for trivial types. – Ted Lyngmo May 30 '23 at 20:59
  • 1
    @Matt Only if the destructor is trivial. – NathanOliver May 30 '23 at 21:00
  • *"OPs code fullfills them all"* Mhm, my point is that this class design is unsound in general, because you can't guarantee that those conditions will always be met. – HolyBlackCat May 30 '23 at 21:09
  • @HolyBlackCat From _"The question is purely theorethical"_ and _"I just want to understand things better"_ I drew the conclusion that this is just a toy example and OP wants to know if what's presented in the question has UB or not. At least, that's how I saw it. – Ted Lyngmo May 30 '23 at 21:17
  • 1
    @TedLyngmo: You saw it right. Thanks. – Dr. Gut May 30 '23 at 23:09