В чем преимущество использования конструктора перемещения по сравнению с передачей указателя?
Foo(Foo&& other) {
this->bar = other.bar;
other.bar = nullptr;
}
Foo(Foo* other) {
this->bar = other->bar;
other->bar = nullptr;
}
Вышеупомянутые два, кажется, делают то же самое. Так почему рекомендуется использовать конструктор перемещения? Какие преимущества это дает?
1 ответ
Причин для использования правильного конструктора перемещения много:
Конвенция. Рассмотрим следующий код:
Foo foo; Foo bar(std::move(foo));
Если вы видите этот код, совершенно ясно, что вы пытаетесь сделать: вы двигаетесь
foo
вbar
, В отличие от:Foo foo; Foo bar(&foo);
Что это значит? Хранит ли указатель на другой
Foo
? ЯвляетсяFoo
какой-то тип узла связанного списка? Вы должны найти это в документации дляFoo
основанный на указателе конструктор.Вы не можете получить указатель на значения.
Foo bar(Foo{})
будет (до C++17) создать временное значение prvalue, а затем перейти от него вbar
(ход может быть исключен до C++17). Но вы не можете сделать это:Foo bar(&Foo{})
,Вы получаете автоматическое движение от вещей, где это имеет смысл. Обобщенное исключение в C++ 17 устраняет многие из этих автоматических движений, но есть некоторые, которые остаются:
Foo function() { Foo foo; //Do stuff return foo; }
Это будет двигаться от
foo
без необходимости звонитьstd::move
, Причина в том, чтоfoo
является локальной переменной, которая собирается быть уничтоженной. Возвращать его таким образом означает, что вполне разумно перейти от него к возвращаемому значению.Ваш путь потребует явного написания
return &foo
, И это делает вещи довольно сложными сauto
возврат типа удержания. Такая функция выведетFoo*
, что означает, что вы только что вернули висячий указатель. Принимая во внимание, что если вы делаетеreturn foo;
, это выводитFoo
prvalue, с автоматическим движением (которое может быть исключено).Нет необходимости
nullptr
чеки. Если вы беретеFoo*
, возможно, что кто-то передаст нулевой указатель. В то время как со ссылкой, это гораздо менее вероятно (и они уже вызвали UB).
Если бы мы хотели переместить поддержку существующих языковых конструкций, мы бы просто использовали неconst
Ссылка означает "двигаться", а не указатель. Придав ему собственный синтаксис, проясните, когда мы что-то перемещаем, а когда нет.