不可抛出的不可移动类的对象

Objects of non-movable classes not throwable?

本文关键字:对象 可移动      更新时间:2023-10-16

当使用 Clang 3.9.1 或 GCC 6.3.0 编译时,抛出可移动但不可复制的对象似乎工作正常:

struct MovableNonCopyable {
    MovableNonCopyable();
    ~MovableNonCopyable();
    MovableNonCopyable(MovableNonCopyable &&);
    MovableNonCopyable(MovableNonCopyable const &) = delete;
    MovableNonCopyable & operator=(MovableNonCopyable &&);
    MovableNonCopyable & operator=(MovableNonCopyable const &) = delete;
};
void f() { throw MovableNonCopyable(); }

但是像这样扔可复制但不可移动的对象:

struct CopyableNonMovable {
    CopyableNonMovable();
    ~CopyableNonMovable();
    CopyableNonMovable(CopyableNonMovable &&) = delete;
    CopyableNonMovable(CopyableNonMovable const &);
    CopyableNonMovable & operator=(CopyableNonMovable &&) = delete;
    CopyableNonMovable & operator=(CopyableNonMovable const &);
};
void g() { throw CopyableNonMovable(); }

而是会导致编译错误,例如:

test.cpp: In function 'void g()':
test.cpp:21:41: error: use of deleted function 'CopyableNonMovable::CopyableNonMovable(CopyableNonMovable&&)'
    void g() { throw CopyableNonMovable(); }
                                        ^
test.cpp:15:9: note: declared here
        CopyableNonMovable(CopyableNonMovable &&) = delete;
        ^~~~~~~~~~~~~~~~~~

这是为什么呢?根据 [except.throw#5],这应该是相反的方式,即复制构造函数应该是可访问的。

在这里,您显式要求编译器阻止来自右值对象的构造。

当您抛出临时CopyableNonMovable()对象时,编译器会为其必须抛出的"副本"查找适当的构造函数。最适合的声明构造函数是移动构造函数,因为右值与右值引用绑定得最好。它查看声明,将其视为已删除,因此必须拒绝它。

最好的解决方案是简单地不声明移动构造函数,这将使它隐不生成,因为声明了复制构造函数。在这种情况下,右值将最好地绑定到对const CopyableNonMoveable