Еще раз об этом, но связанные вопросы не отвечают на мой вопрос.
Стандарт довольно понятен:
12.8 Копирование и перемещение объектов класса,
§9
Если определение класса X явно не объявляет конструктор перемещения, он будет неявно объявлен как дефолтный, если и только если
— X не имеет объявленного пользователем конструктора копирования,
— X не имеет заявленного пользователем оператора копирования,
— X не имеет объявленного пользователем оператора назначения перемещения,
— X не имеет объявленного пользователем деструктора, и
— конструктор перемещения не будет неявно определен как удаленный.
[Примечание: Когда конструктор перемещения не объявляется неявным образом или не предоставляется явно, выражения, которые в противном случае вызвали бы конструктор перемещения, могут вместо этого вызывать конструктор копирования. — конец примечания]
Поэтому, прежде чем заметить «Note» в конце, я ожидал, что этот фрагмент кода не будет компилироваться (хотя я знал, что перемещение должен откат к копированию):
#include <iostream>
using std::cout;
class c
{
public:
c() { cout << "c::c()\n"; }
c( std::initializer_list< int > ) { cout << "c::c( std::initializer_list )\n"; };
c( const c& ) { cout << "c::c( const c& )\n"; }
c& operator=( const c& ) { cout << "c& c::operator=( const c& )\n"; return *this; }
~c() { cout << "c::~c()\n"; }
void f() {}
};
void f( c&& cr ) { cout << "f()\n"; cr.f(); }
int main()
{
c x;
f( std::move( x ) );
return 0;
}
Затем я увидел примечание в конце, но я все еще был удивлен, что код выше выводит:
с :: с ()
F ()
с :: ~ с ()
Обратите внимание на «пропавших без вести» c::c( const c& )
, Потом я добавил
c( c&& ) = delete;
c& operator=( c&& ) = delete;
и результат все тот же.
Что мне здесь не хватает?
$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609
Флаги компилятора: -s -O0 -march=native -pthread -std=c++11 -Wall -Wextra -DNDEBUG
,
cr
Параметр из вашего примера является r-значением ссылка. Справочное слово здесь важно. Он действует подобно плоской старой ссылке, которую мы знаем из c ++, до того, как c ++ 11 появился в игре, в терминах, которые он не вызывает ни в каком конструкторе … он просто «указывает» на объект, который вы передаете. ..
Чтобы вызвать движущийся конструктор (или выполнить другой обмен) и использовать ссылку, нам нужно переслать ссылку далее, например, следующее:
void f( c&& cr ) {
c cr2(std::move(cr));
}
Вы не двигали ни одного объекта.
std::move
на самом деле довольно запутанно, потому что ничего не двигает. только Move-конструктор или оператор присваивания перемещения могут перемещать объекты, что std::move
do просто приводит ссылку на l-значение (&
) к r-значению-ссылке (&&
).
конструктор перемещения или оператор присваивания перемещения могут связываться с r-value-referencence (&&
) и украсть содержимое объекта.