Переместить объект без конструктора перемещения

Еще раз об этом, но связанные вопросы не отвечают на мой вопрос.

Стандарт довольно понятен:

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,

3

Решение

cr Параметр из вашего примера является r-значением ссылка. Справочное слово здесь важно. Он действует подобно плоской старой ссылке, которую мы знаем из c ++, до того, как c ++ 11 появился в игре, в терминах, которые он не вызывает ни в каком конструкторе … он просто «указывает» на объект, который вы передаете. ..

Чтобы вызвать движущийся конструктор (или выполнить другой обмен) и использовать ссылку, нам нужно переслать ссылку далее, например, следующее:

void f( c&& cr ) {
c cr2(std::move(cr));
}
7

Другие решения

Вы не двигали ни одного объекта.

std::move на самом деле довольно запутанно, потому что ничего не двигает. только Move-конструктор или оператор присваивания перемещения могут перемещать объекты, что std::move do просто приводит ссылку на l-значение (&) к r-значению-ссылке (&&).

конструктор перемещения или оператор присваивания перемещения могут связываться с r-value-referencence (&&) и украсть содержимое объекта.

8

По вопросам рекламы [email protected]