Является ли конструктор перемещения` =default ' эквивалентным конструктору перемещения по элементам?
это
struct Example {
int a, b;
Example(int mA, int mB) : a{mA}, b{mB} { }
Example(const Example& mE) : a{mE.a}, b{mE.b} { }
Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
Example& operator=(const Example& mE) { a = mE.a; b = mE.b; return *this; }
Example& operator=(Example&& mE) { a = move(mE.a); b = move(mE.b); return *this; }
}
эквивалентной
struct Example {
int a, b;
Example(int mA, int mB) : a{mA}, b{mB} { }
Example(const Example& mE) = default;
Example(Example&& mE) = default;
Example& operator=(const Example& mE) = default;
Example& operator=(Example&& mE) = default;
}
?
4 ответа:
да оба одинаковые.
но
struct Example { int a, b; Example(int mA, int mB) : a{mA}, b{mB} { } Example(const Example& mE) = default; Example(Example&& mE) = default; Example& operator=(const Example& mE) = default; Example& operator=(Example&& mE) = default; }
эта версия позволит вам пропустить определение тела.
однако, вы должны следовать некоторым правилам, когда вы объявляете
explicitly-defaulted-functions
:8.4.2 явно-функции по умолчанию [dcl.ПКТ.защита.по умолчанию]
определение функции формы:
attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt = default ;
называется явно-по умолчанию определение. Один функция, которая явно по умолчанию должна
быть специальной функцией-членом,
имеют один и тот же объявленный тип функции (за исключением, возможно, отличающихся ref-квалификаторы и за исключением того, что в случае конструктора копирования или оператора присваивания копирования тип параметра может быть "ссылка на неконст
T
", гдеT
- это имя класса функции-члена), как если бы оно было неявно объявлено,нет аргументов по умолчанию.
Да, конструктор перемещения по умолчанию будет выполнять перемещение по элементам своей базы и членов, поэтому:
Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
эквивалентно:
Example(Example&& mE) = default;
мы можем увидеть это, перейдя к проект стандарта C++11 раздел
12.8
копирование и перемещение объектов класса абзац 13 где сказано (акцент мой идет вперед):конструктор копирования / перемещения, который по умолчанию не определен как удаленный неявно определенными если это odrused (3.2) или, когда это явно дефолт после его первого объявления. [ Примечание: копирование / перемещение конструктор неявно определен, даже если реализация elided его Усо-использовать (3.2, 12.2). -конец Примечание ][...]
и пункта 15 он говорит:
The неявно определенный конструктор копирования/перемещения для несоюзного класса X выполняет memberwise копирование / перемещение его баз и членов. [ Отмечать: бандаж или равно инициализатор нестатических членов данных игнорируются. См. также пример в 12.6.2. -конец Примечание ] порядок инициализация такая же, как и порядок инициализации баз и элементы в определяемом пользователем конструкторе (см. 12.6.2). Пусть x быть параметр конструктора или конструктора перемещения, в xvalue, ссылающийся на параметр. Каждый базовый или нестатический элемент данных копируется / перемещается таким образом соответствующий его типу:
- если элемент является массивом, каждый элемент непосредственно инициализируется соответствующим подобъектом x;
- если элемент m имеет ссылочный тип rvalue T&&, он инициализируется напрямую с помощью static_cast (x. m);
- в противном случае база или элемент инициализируется напрямую с помощью соответствующей базы или элемента x.
виртуальные субобъекты базового класса инициализируются только один раз неявно определенный конструктор копирования / перемещения (см. 12.6.2).
это
=default
конструктор перемещения эквивалентен конструктору перемещения по элементам?
да. обновление: Ну, не всегда. Посмотрите на этот пример:#include <iostream> struct nonmovable { nonmovable() = default; nonmovable(const nonmovable &) = default; nonmovable( nonmovable &&) = delete; }; struct movable { movable() = default; movable(const movable &) { std::cerr << "copy" << std::endl; } movable( movable &&) { std::cerr << "move" << std::endl; } }; struct has_nonmovable { movable a; nonmovable b; has_nonmovable() = default; has_nonmovable(const has_nonmovable &) = default; has_nonmovable( has_nonmovable &&) = default; }; int main() { has_nonmovable c; has_nonmovable d(std::move(c)); // prints copy }
он печатает:
copy
http://coliru.stacked-crooked.com/a/62c0a0aaec15b0eb
вы объявили конструктор перемещения по умолчанию, но копирование происходит вместо перемещения. Зачем? Потому что если класс имеет даже один не-движимости членом то явно дефолт переместить конструктор имплицитно удалены (такой каламбур). Поэтому, когда вы бежите
has_nonmovable d = std::move(c)
, конструктор копирования фактически вызывается, потому что конструктор перемещенияhas_nonmovable
удаляется (неявно), он просто не существует (даже если вы явно объявили конструктор перемещения выражениемhas_nonmovable(has_nonmovable &&) = default
).но если конструктор перемещения
non_movable
не было объявлено вообще, конструктор перемещения будет использоваться дляmovable
(и для каждого члена, который имеет конструктор перемещения) и конструктор копирования будет использоваться дляnonmovable
(и для каждого члена, который не определите конструктор перемещения). Смотрите пример:#include <iostream> struct nonmovable { nonmovable() = default; nonmovable(const nonmovable &) { std::cerr << "nonmovable::copy" << std::endl; } //nonmovable( nonmovable &&) = delete; }; struct movable { movable() = default; movable(const movable &) { std::cerr << "movable::copy" << std::endl; } movable( movable &&) { std::cerr << "movable::move" << std::endl; } }; struct has_nonmovable { movable a; nonmovable b; has_nonmovable() = default; has_nonmovable(const has_nonmovable &) = default; has_nonmovable( has_nonmovable &&) = default; }; int main() { has_nonmovable c; has_nonmovable d(std::move(c)); }
он печатает:
movable::move nonmovable::copy
http://coliru.stacked-crooked.com/a/420cc6c80ddac407
обновление: но если вы прокомментируете строку
has_nonmovable(has_nonmovable &&) = default;
, тогда копия будет использоваться для обоих участники:http://coliru.stacked-crooked.com/a/171fd0ce335327cd - отпечатки пальцев:movable::copy nonmovable::copy
так что, вероятно, положить
=default
везде все еще имеет смысл. Это не означает, что ваши выражения движения всегда будут двигаться, но это делает шансы на это выше.еще одно обновление: но если закомментировать строку
has_nonmovable(const has_nonmovable &) = default;
либо, то результат будет:movable::move nonmovable::copy
так что если вы хотите знать, что происходит в вашей программе, просто делать все по себе: вздох: