Безопасно ли полагаться на неявно объявленный конструктор перемещения?
Вот где я получил большую часть этой информации: http://en.cppreference.com/w/cpp/language/move_constructor
По-видимому, это условия для неявно сгенерированного конструктора перемещения:
- нет никаких заявленных пользователем конструкторов копирования
- нет заявленных пользователем операторов копирования
- нет пользовательских операторов перемещения
- нет деструкторов, объявленных пользователем
- неявно объявленный конструктор перемещения не определен как удаленный
- если присутствует объявленный пользователем конструктор перемещения, все еще возможно принудительно генерировать неявно объявленный конструктор перемещения с ключевым словом
default
Мои вопросы:
- Безопасно ли полагаться на неявный конструктор автоматического перемещения?
- Как проверить, действительно ли это работает вместо конструктора копирования по умолчанию?
- Наконец, и самое главное, это хорошая идея и почему? Или всегда лучше определить свое?
Я более склонен следовать правилу трех и вручную создавать деструктор, конструктор копирования и перемещения и оператор присваивания копирования и перемещения, но мне просто любопытно это неявное.
2 ответа
Вот ответы на ваши вопросы:
- Что вы имеете в виду под "безопасным"? Когда применяются правила, то есть подобъекты являются подвижными, и вы ничего не сделали, чтобы помешать генерации конструктора перемещения, он будет создан и использован при его наличии. Однако обратите внимание, что легко иметь неподвижный подобъект, который будет несколько незаметно препятствовать созданию конструктора перемещения.
- Чтобы увидеть, получил ли ваш класс конструктор перемещения, просто временно добавьте пустую базовую запись в журнал, когда используются копия и конструкторы перемещения, и принудительно переместите / скопируйте объект: он запишет соответствующий используемый конструктор.
- Нет кода, как правило, лучше, чем любой код.
1
, Безопасно ли полагаться на неявный конструктор автоматического перемещения?
Ничто не является безопасным, на которое можно положиться без тестирования (неявного или явного).
2
, Как проверить, действительно ли это работает вместо конструктора копирования по умолчанию?
Тестирование. Смотрите пример теста ниже.
3
, Наконец, и самое главное, это хорошая идея и почему? Или всегда лучше определить свое?
Есть определенные (и растущие) преимущества, которые делают ваши специальные члены тривиальными. Тривиальный специальный член - тот, который определен / предоставлен компилятором. Вы можете объявить тривиальный член с = default
, На самом деле это последнее предложение является преувеличением. Если вы объявите специального члена с = default
это точно не будет тривиальным. Это зависит от ваших членов и баз. Но если вы определите специальный член явно (как в C++98/03), то наверняка он не будет тривиальным. Если у вас есть выбор между предоставленным пользователем и тривиальным, предпочтите тривиальный.
Кроме того, вам не нужно проверять, если ваш тип X
имеет конструктор перемещения. Вы должны проверить это, если вы двигаетесь X
То, что у него есть правильное исключение безопасности и правильное исполнение. Если X::X(const X&)
выполняет эту задачу, пусть будет так. В таком случае X::X(X&&)
не обязательно.
Если вы ожидаете, что ваш тип X
будет иметь конструктор метания копии, и гораздо быстрее noexcept
Конструктор перемещения, вот действительно хороший тест, чтобы подтвердить, что это так:
static_assert(std::is_nothrow_move_constructible<X>::value,
"X should move construct without an exception");
Поместите этот тест прямо в ваш источник / заголовок. Теперь, независимо от того, неявно ли вы, явно или явно объявляете или определяете свои специальные члены, у вас есть конкретный тест во время компиляции, который практически не требует затрат. static_assert
генерирует нулевой код и потребляет незначительное количество времени компиляции.