Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Destroy-and-regenerate assignment operator: what if I'm careful?

This is a bad pattern. Copy-and-swap is better.

foo & operator = ( foo const & other ) {
    static_assert ( noexcept( new (this) foo() ), "Exception safety violation" );

    this-> ~ foo();
    try {
        new (this) foo( other );
    } catch (...) {
        new (this) foo(); // does not throw
        throw;
    }
    return * this;
}

As long as foo is not polymorphic, what could go wrong? (However, assume that it is a base class.)

Background: I'm dealing with local-storage type erasure, and the alternative is to implement swap as two hard-coded assignments through a local storage space. The objects in the memory blobs of the source and destination are of different types and simply can't swap with each other. Copy/move construction defined in terms of such a swap is twice as complicated for seemingly no gain.

like image 258
Potatoswatter Avatar asked May 26 '15 14:05

Potatoswatter


Video Answer


1 Answers

The standard makes guarantees about such interrupted lifetimes in [basic.life] §3.8/7:

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 storage for the new object exactly overlays the storage location which the original object occupied, and

— the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and

— 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

— the original object was a most derived object (§1.8) of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).

The last point disqualifies my use-case. However, since this is only for one non-polymorphic class, it's just as well to turn the destructor and constructors into destroy and init private member functions, respectively.

In other words, when destroy-and-regenerate is legal, you might as well do the same thing using member functions and no new/delete.

An "advantage" to this is that it ceases to look clever, so no ignorant passer-by would want to copy the design.

like image 101
Potatoswatter Avatar answered Oct 07 '22 16:10

Potatoswatter