给出以下代码(http://liveworkspace.org/code/5oact):
class Foo
{
public:
Foo()
{
log(__PRETTY_FUNCTION__);
}
Foo(const Foo& other)
{
log(__PRETTY_FUNCTION__);
}
Foo& operator=(const Foo& other)
{
log(__PRETTY_FUNCTION__);
return *this;
}
Foo(Foo&& other) noexcept
{
log(__PRETTY_FUNCTION__);
}
Foo& operator=(Foo&& other) noexcept
{
log(__PRETTY_FUNCTION__);
return *this;
}
~Foo(){}
};
使用这样的类:
std::vector<Foo> tt;
tt.emplace_back();
tt.emplace_back();
tt.emplace_back();
tt.emplace_back();
我得到以下输出:
Foo::Foo()
Foo::Foo()
Foo::Foo(const Foo&)
Foo::Foo()
Foo::Foo(const Foo&)
Foo::Foo(const Foo&)
Foo::Foo()
如果我删除自定义析构函数,我会得到以下输出:
Foo::Foo()
Foo::Foo()
Foo::Foo(Foo&&)
Foo::Foo()
Foo::Foo(Foo&&)
Foo::Foo(Foo&&)
Foo::Foo()
为什么编译器在声明析构函数时使用复制构造函数而不是移动?我理解移动操作不能抛出(如果我从代码中删除noexcept
,编译器根本不会使用它),但是析构函数与它有什么关系?
答案 0 :(得分:6)
首先,您的编译器似乎存在使用错误的noexcept规范的问题。根据标准, 12.4.3 :
没有 exception-specification 的析构函数声明被隐式地认为具有与隐式声明相同的 exception-specification
如果所有成员和基础的析构函数都是noexcept
,则析构函数的隐式声明将为noexcept
。所以你的显式析构函数声明应该等同于:
~Foo() noexcept {} // or:
~Foo() noexcept(true) {}
但您的编译器将其视为:
~Foo() noexcept(false) {}
其次,析构函数的异常 - 规范影响决定是否移动的原因是因为操作中涉及破坏。就像 move-constructor 上的noexcept
和 move-assignment 操作影响决策一样,如果有可能存在异常,则不会使用move可能会在进程中抛出。