C++ 中 `delete this` 和 `this->~Obj` 之间的区别

ln *_* vv 1 c++ memory-management double-free assignment-operator delete-operator

当我编写一个演示字符串类时,在复制赋值函数中,我尝试在复制之前通过“删除此”来清除自身。但它失败了。

    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;
    }
Run Code Online (Sandbox Code Playgroud)

linux 告诉我的

双释放或损坏(出)中止(核心转储)

Hol*_*Cat 7

delete x;相当于x->~T();其次operator delete(x)(与 类似free(x),但可能与之不兼容)。

x->~T();是一个危险的工具。在这种情况下,必须紧跟new(this) T(...);(placement-new) 来调用构造函数,否则当前对象被认为是“死的”,并且与它的任何交互都会导致未定义的行为。

但即使你确实调用了placement-new,它也可能会抛出异常。然后该对象仍然处于死亡状态,并且当调用者尝试再次销毁已经死亡的对象时,它会得到 UB。

结论:x->~T();很难正确使用,请使用其他东西。

  • 要么编写一个与析构函数执行相同操作的函数,然后调用它。与析构函数不同,调用该对象后不会被视为已死亡,因此不需要放置新对象。

  • 或者使用复制和交换习惯用法。将作业写为:

    Str &operator=(Str s) noexcept
    {
        std::swap(_str, s._str);
        std::swap(_size, s._size);
        return *this;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这是撰写作业的通用方法。它既可以用作复制分配,也可以用作移动分配,并且是异常安全的,等等。