4

给定以下代码(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从代码中删除,编译器根本不会使用它),但是析构函数与它有什么关系呢?

4

1 回答 1

6

首先,您的编译器似乎存在使用错误 noexcept 规范的问题。根据标准,12.4.3

没有异常规范的析构函数声明被隐式认为具有与隐式声明相同的异常规范

noexcept如果所有成员和基的析构函数也是如此,则析构函数的隐式声明将是noexcept。因此,您的显式析构函数声明应等效于:

~Foo() noexcept {} // or:
~Foo() noexcept(true) {}

但是您的编译器将其视为:

~Foo() noexcept(false) {}

其次,析构函数异常规范影响是否移动的决定的原因是因为操作中涉及到析构。正如移动构造函数移动赋值操作会影响决策一样,如果有可能在过程中抛出异常,则不会使用移动。noexcept

于 2013-02-17T19:23:30.937 回答