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.
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 typeT
(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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With