2016-12-12 11 views
2

Еще раз об этом, но связанные вопросы не отвечают на мой вопрос.Переместить объект без перемещения конструктора

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

12,8 Копирование и перемещение объектов класса,
§9
Если определение класса X не явно объявить конструктор перемещения, один будет неявно объявлен как установлено по умолчанию, если и только если
- X не имеет объявленного пользователем конструктора копирования,
- X не имеет объявленного пользователем оператора копирования копий,
- X не имеет объявленного пользователем mo ve,
- X не имеет объявленного пользователем деструктора, а
- конструктор перемещения не будет неявно определен как удаленный.
[Примечание: если конструктор перемещения неявно объявлен или явно указан, выражения, которые в противном случае вызывают конструктор перемещения, могут вместо этого вызвать конструктор копирования. - конец примечание]

Поэтому, прежде чем замечать «Примечание» в конце концов, я ожидал этот кусок кода на провал компиляции (хотя я знал, что перемещение должен запасного варианта для копирования):

#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; 
} 

Потом я увидел записку в конце, но я все еще был удивлен, что приведенный выше код выхода:

с :: с()
е()
c :: ~ c()

Обратите внимание на «недостающие» 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.

+4

'cr' является г-значение ** ссылка **, которая еще не потребляется любого конструктора ... –

+0

@ W.F. - О, мой, пожалуйста, отправьте это как ответ. Ты ужасно прав. (Добавление 'c xx (std :: move (x));' вместо использования 'f (c &&)' генерирует ожидаемое поведение. –

+0

это непростой вопрос XD – Stargateur

ответ

6

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

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

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

Вы не перемещали объект.

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

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

+0

Это действительно приятное объяснение, которое прекрасно дополняет принятый ответ. +1, спасибо –