移动赋值运算符异常

Exception in move assignment operator

考虑:

struct Boo {
    Boo (std::string v) : src {v} {}

    Boo (const Boo&) = delete;
    Boo& operator= (const Boo&) = delete;

    Boo (Boo&& b) : src {std::move (b.src)} {}

    Boo& operator= (Boo&& b) {
        if (this != &b) {
            foo ();
            src = std::move (b.src);
        }
        return *this;
    }

    void show () {
        std::cout << "|" << src << "|" << std::endl;
    }

    void foo () {
        throw 1;
    }

    std::string src {};
};

和用法:

int main(int argc, char** argv) {

    Boo s {"Boo1"};
    Boo p {"Boo2"};

    try {
        p = std::move (s); // (X)
    }
    catch (...) {}

    s.show ();
    p.show ();

    return 0;
}

输出如下所示:

如果在移动赋值运算符中调用foo()

|Boo1|
|Boo2|

如果foo()没有被调用

|Boo2|
|Boo1|

问题:

移动赋值运算符抛出异常时s会发生什么?它是否像在第(X)行使用std::move()之前一样有以前的内容,或者内容完全移动到b(函数参数)?

为什么在这两种情况下输出都显示内容仍在 std::string 个对象中?

当抛出异常时,正常执行立即停止,调用堆栈展开。直到第一个有效的catch。对于您的情况,这意味着一旦您 throw 继续执行 foo 和赋值运算符函数就会停止,并且程序会转到 main 中的 catch函数,换句话说,不会发生任何会改变对象的事情。

移动 std::string 对象会使源处于有效但 未指定 状态。应该注意的是,移动通常通过 交换 源和目标来实现,这将解释您看到的行为。