When I am writing a demo string class, in the copy assignment function, I try to clear itself through 'delete this' before copy.But it failed.
Str &operator=(const Str &s) {
if (this != &s) { // self-assignment check
//delete this; //cannot run as I imagine
this->~Str();
_size = s._size;
_str = new char[_size + 1];
memcpy(_str, s._str, _size + 1);
}
return *this;
}
~Str() {
_size = 0;
delete[] _str;
}
the linux told me
double free or corruption (out) Aborted (core dumped)
delete x;
is equivalent to x->~T();
followed by operator delete(x)
(which is similar to free(x)
, but might be incompatible with it).
x->~T();
is a dangerous tool. In this case it must be followed by new(this) T(...);
(placement-new) to call a constructor, otherwise the current object is considered to be "dead", and any interaction with it causes undefined behavior.
But even if you do call placement-new, it can throw. Then the object remains dead, and the caller gets UB when it tries to destroy the already dead object again.
Conclusion: x->~T();
is hard to use correctly, use something else.
Either write a function that does the same thing as the destrutor, and call it instead. Unlike the destructor, the object wouldn't be considered dead after calling it, so no placement-new is needed.
Or use the copy&swap idiom. Write the assignment as:
Str &operator=(Str s) noexcept
{
std::swap(_str, s._str);
std::swap(_size, s._size);
return *this;
}
This is an universal way of writing assignments. It works both as copy and move assignment, is exception-safe, etc.