Пока я учился std::move
Я нашел странную проблему.
Если я добавлю только деструктор, который ничего не делает с идеальной программой, я получу ошибку компиляции.
#include <iostream>
using namespace std;
class M {
public:
int database = 0;
M &operator=(M &&other) {
this->database = other.database;
other.database = 0;
return *this;
}
M(M &&other) { *this = std::move(other); }
M(M &m) = default;
M() = default;
~M() { /* free db */ }
};
class B {
public:
M shouldMove;
//~B(){} //<--- ## Adding this line will cause compile error. ##
};
int main() {
B b;
B b2 = std::move(b); //## error at this line if the above line is added
return 0;
}
Живой код: https://ideone.com/UTR9ob
Ошибка invalid initialization of non-const reference of type 'B&' from an rvalue of type 'std::remove_reference<B&>::type {aka B}'
,
B
Должен ли я действительно следовать правило пяти вместо? Если нет, как заставить его скомпилировать? Следование правилу пяти только из-за этого, на мой взгляд, слишком утомительно и грязно.Я думаю правило нуля это просто хорошая практика.
Однако из этого примера мне кажется, что это жесткое правило, что в случае нарушения я получу ошибку компиляции.
Неявно объявленный конструктор перемещения присутствует, только если класс не имеет объявленного пользователем деструктора. Поэтому ответ на вопрос 2. ДА.
Ответ на 1. состоит в том, что это жесткое правило, и его можно найти в пункте 12.8 стандарта:
Если определение класса X явно не объявляет конструктор перемещения, он будет неявно объявлен
по умолчанию, если и только если[Примечание: когда конструктор перемещения не объявлен неявно или не предоставлен явно, выражения, которые
- X не имеет объявленного пользователем конструктора копирования,
- X не имеет заявленного пользователем оператора копирования,
- X не имеет объявленного пользователем оператора назначения перемещения,
- X не имеет объявленного пользователем деструктора, и
- конструктор перемещения не будет неявно определен как удаленный.
в противном случае вызвал бы конструктор перемещения, может вместо этого вызвать конструктор копирования. — конец примечания]
Лучший способ заставить это работать, это использовать что-то вроде умного указателя, то есть базовый класс или член, который определяет все пять специальных членов (и очень мало других), так что вам не нужно это делать. В этом случае целочисленный дескриптор эквивалентен std::unique_pointer
должно хорошо работать. Однако имейте в виду, что базы данных, как и файлы, могут иметь ошибки при закрытии, поэтому стандартная семантика деструктора без выбрасывания не охватывает все случаи.
Других решений пока нет …