Начиная с C++17 значение prvalue изменилось, что в некоторых случаях гарантирует исключение копирования. Из cppreference конструкторы копирования/перемещения не обязательно должны присутствовать или быть доступными в этом случае.
При возникновении исключения объект исключения инициализируется копированием, и при копировании/перемещении может возникнуть ошибка копирования. Но требуется ли, чтобы в это время был доступен конструктор копирования/перемещения?
От [кроме.throw]:
Когда брошенный объект является объектом класса, конструктор, выбранный для инициализации копирования, а также конструктор, выбранный для инициализации копирования, рассматривающий брошенный объект как lvalue, должен быть неудаляемым и доступным, даже если операция копирования/перемещения опущена ([class.copy.elision]). Деструктор потенциально вызывается ([class.dtor]).
В стандарте упоминается, что соответствующий конструктор не должен удаляться и быть доступным, даже если он опущен.
Тем не менее, я протестировал и обнаружил, что и GCC, и Clang позволяют создавать исключения при удалении соответствующего конструктора:
struct A {
A() = default;
A(A&&) = delete;
};
try {
throw A{}; // copy elision
} catch(...) {}
Код компилируется, но не соответствует требованиям стандарта. Если я уменьшу версию с C++17 до C++14, они оба сообщат об ошибках:
struct A {
A() = default;
A(A&&) = delete;
};
try {
throw A{}; // error: call to deleted constructor of 'A'
} catch(...) {}
Я неправильно понимаю стандарт или компилятор просто ослабляет ограничения?
Спасибо. Я понял ваш ответ. Итак, выбранный конструктор в этом примере является просто конструктором по умолчанию? Кроме того, можете ли вы объяснить или привести пример о том, что «конструктор, выбранный для инициализации копирования, рассматривает брошенный объект как lvalue»?