2017-01-30 16 views
4

При компиляции с Clang 3.9.1 или 6.3.0 НКУ бросать подвижные, но не Copyable объекты, кажется, работает нормально:Объекты недвигаемых классов, не поддающиеся качению?

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

void f() { throw MovableNonCopyable(); } 

Но метательные Copyable но не подвижные объекты, как это:

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] это должно быть наоборот, то есть конструктор копирования должен быть доступен.

+2

Что делать, если вы явно не «удаляете» конструкторы перемещения? Я предполагаю, что в качестве резервной копии потребуются копии конструкторов. Но здесь вы явно запрещаете строить из rvalues. – KABoissonneault

+0

@ KABoissonneault Вы правы. Если я явно удалю их, резервное копирование не будет работать. Сделайте это хорошим ответом, и я приму это. – jotik

ответ

2

Здесь вы явно просите компилятор предотвратить конструкцию из объектов rvalue.

Когда вы бросаете свой временный объект CopyableNonMovable(), компилятор ищет соответствующий конструктор для своей «копии», которую он должен бросить. Объявленный конструктор, который лучше всего подходит, - это конструктор перемещения, поскольку rvalues ​​лучше всего привязывают ссылки к rvalue. Он рассматривает декларацию, считает ее удаленной, и поэтому должен ее отказать.

Лучшим решением является просто не объявлять конструктор перемещения, который сделает его неявным не сгенерирован, так как был объявлен конструктор копирования. В этом случае значения r будут наилучшим образом привязываться к ссылке const CopyableNonMoveable