C++ noexcept与移动语义:保证异常安全 #
引言 #
在C++中,noexcept修饰符不仅是一个简单的声明,它还与移动语义和容器的异常安全性密切相关。
之前在训练营和大家一起讨论过vector等动态扩容容器的扩容机制,结论是可以move的话,会优先move,其次才是copy。
为什么可以move,需要定义类的移动构造函数,看这段代码:
struct Foo {
Foo() {}
~Foo() noexcept {}
Foo(const Foo&) {
std::cout << "copy \n";
}
Foo(Foo&&) {
std::cout << "move \n";
}
};
int main() {
std::vector<Foo> v;
for (int i = 0; i < 3; ++i) {
v.emplace_back();
}
}
然而这里输出的都是copy,和上述的结论貌似不符。
我们再稍微改动一下代码:
struct Foo {
Foo() {}
~Foo() noexcept {}
Foo(const Foo&) {
std::cout << "copy \n";
}
Foo(Foo&&) noexcept {
std::cout << "move \n";
}
};
这时输出的都是move。
这里唯一的改动就是为移动构造函数添加了 noexcept 修饰。只有它使用noexcept修饰,只有在保证不抛出异常的情况下( 强异常安全保证),自动扩容时才会选择move语义,这就叫move_if_noexcept。
那为什么要有move_if_noexcept?
具体可以看看这两个文档:
- cppreference.com/w/cpp/utility/move_if_noexcept
- stackoverflow.com/questions/28627348/noexcept-and-copy-move-constructors