Учитывая этот минимальный пример:
#include <iostream>
#include <stdexcept>
using std::cout;
using std::endl;
using std::runtime_error;
struct MyObj
{
MyObj() { cout << "constructed\n";}
MyObj(const MyObj& r) { cout << "copied\n"; }
MyObj(MyObj&& r) noexcept { throw runtime_error("I should terminate the program if uncaught"); }// = delete;
};
void Test(MyObj value)
{
cout << "called\n";
}
int main()
{
Test(MyObj());
return 0;
}
Здесь я (полагаю) реализую все конструкторы, которые были бы реализованы компилятором, если бы их не было. Я также подтвердил, что могу заставить каждого выполнить традиционные заклинания. Причина моего заблуждения заключается в том, что же делает main
.
Test
требует, чтобы любое переданное ему выражение после вычисления можно было использовать для построения дискретного и независимого значения MyObj
. Моя передача ранее несуществующей конструкции по умолчанию должна дать ссылку на r-значение &&
.
Попытка построить значение из &&
- это идеальное совпадение сигнатуры с реализованным конструктором перемещения. Фактически, если я объявляю этот конструктор удаленным (= delete;
), компилятор завершается с ошибкой, говоря, что указанная функция была удалена., что указывает на то, что мои рассуждения, по крайней мере, в некоторой степени верны.
Однако, когда я объявляю функцию, как написано в примере кода, реализация предназначена для завершения программы в случае ее выполнения ... ничего не происходит. Сначала я пробовал cout
, чтобы отразить другие конструкторы, но ничего не вышло, поэтому я добавил runtime_error
для повышения ставки или анти в данном случае. Тем не менее, компилятор предупреждает, что функция, объявленная noexcept
, наверняка выбрасывает ее, но все равно компилируется и запускается, выводя:
constructed
called
У меня осталось два вопроса.
Почему компилятор не работает, утверждая, что я ссылаюсь на удаленную функцию, если исполняемый файл явно никогда не вызовет ее (в случае =delete;
)?
Как значение параметра в Test
инициализируется из ссылки на r-значение, если не копировать и не перемещать?
NB: это MSVC 14.11.25503, размещенный на VS2017.
Редактировать: Я просто хочу уточнить, учитывая спецификацию noexcept
, что throw
должен завершить программу в любом случае.
@schulmaster Да. Прочтите пост. "Если вызов конструктора копирования или перемещения опущен, этот конструктор должен все еще существовать и быть доступным. Это гарантирует, что исключение копирования не позволяет копировать объекты, которые обычно не копируются, например, потому что они имеют частную или удаленную копию / перемещение. конструктор."
Я слышал о копировальной элизии, но никогда еще она не проявлялась так открыто. Позвольте мне тогда спросить: может ли компилятор выйти из строя из-за ошибок, которые он сам полностью устранит?