C++中'delete this'和'this->~Obj'的区别

jtw3ybtb  于 2023-02-14  发布在  其他
关注(0)|答案(2)|浏览(112)

当我在写一个字符串类的演示时,在复制赋值函数中,我试图在复制前通过“删除这个”来清除自己,但是失败了。

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;
    }

Linux告诉我
双重释放或损坏(输出)已中止(核心转储)

yqlxgs2m

yqlxgs2m1#

delete x;等效于x->~T();后跟operator delete(x)(类似于free(x),但可能不兼容)。
x->~T();是一个危险的工具,在这种情况下它必须跟在new(this) T(...);(placement-new)后面才能调用构造函数,否则当前对象被认为是“死的”,与它的任何交互都会导致未定义的行为。
但是即使你调用placement-new,它也会抛出,然后对象保持死状态,当调用者试图再次销毁已经死了的对象时,调用者会得到UB。
结论:x->~T();很难正确使用,使用其他东西。

  • 要么写一个函数做和析构函数一样的事情,然后调用它,不像析构函数,对象在调用后不会被认为是死的,所以不需要placement-new。
  • 或者使用copy&swap的习惯用法,将赋值语句写成:
Str &operator=(Str s) noexcept
{
    std::swap(_str, s._str);
    std::swap(_size, s._size);
    return *this;
}

这是写赋值语句的一种通用方法。它既可以用作复制赋值语句,也可以用作移动赋值语句,而且是异常安全的,等等。

plupiseo

plupiseo2#

你的delete this已经执行了this->~Str(),但这只是一个问题。在delete this之后,你调用了_size = s._size,它实际上是this->_size = s._size。但是this的生存期已经结束,所以任何对this的调用都可能导致未定义的行为。所以delete thisthis->~Str()都不属于你的赋值运算符。

相关问题