移动赋值运算符中的异常

时间:2015-12-21 15:03:54

标签: c++ move-semantics

考虑:

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个对象中?

1 个答案:

答案 0 :(得分:3)

当抛出异常时,正常执行立即停止,并且调用堆栈被展开。直到第一个有效catch。对于您的情况,这意味着只要您throw暂停继续执行foo和分配运算符函数,程序就会转到catch中的main功能,换句话说,什么都不会改变对象。

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