Рассмотрим следующие классы.
struct with_copy {
with_copy() = default;
with_copy(with_copy const&) {}
with_copy& operator=(with_copy const&) { return *this; }
};
struct foo {
with_copy c;
std::unique_ptr<int> p;
};
with_copy
есть конструктор копирования? Да. Это было явно определено.with_copy
есть конструктор ходов? Нет. Явный конструктор копирования предотвращает его создание.with_copy
есть удаленный конструктор перемещения? Нет. Отсутствие конструктора перемещения — это не то же самое, что удаление удаленного. Удаленный конструктор перемещения будет пытаться переместить плохо сформированную копию вместо вырожденной в копию.with_copy
Copyable? Да. Его конструктор копирования используется для копий.with_copy
Подвижный? Да. Его конструктор копирования используется для ходов.… а теперь хитрые.
foo
есть конструктор копирования? Да. У него есть удаленный, так как его дефолтное определение будет неправильно сформировано из-за вызова unique_ptr
Конструктор удаленных копий.foo
есть конструктор ходов? GCC говорит да, лязг говорит нет.foo
есть удаленный конструктор перемещения? И GCC, и Clang говорят нет.foo
Copyable? Нет. Его конструктор копирования удален.foo
Подвижный? GCC говорит да, лязг говорит нет.(Поведение аналогично, когда рассматривается назначение вместо конструкции.)
Насколько я вижу, GCC является правильным. foo
должен иметь конструктор перемещения, который выполняет перемещение для каждого члена, который в with_copy
Дело вырождается в копию. Поведение Кланга кажется довольно нелепым: у меня есть агрегат с двумя подвижными элементами, и все же мой агрегат является неподвижным кирпичом.
Кто прав?
C ++ 11, а точнее n3485, [class.copy] / 9:
Если определение класса
X
явно не объявляет конструктор перемещения, один будет неявно объявлен
по умолчанию, если и только если
X
не имеет объявленного пользователем конструктора копирования,X
не имеет заявленного пользователем оператора копирования,X
не имеет объявленного пользователем оператора назначения перемещения,X
не имеет объявленного пользователем деструктора, и- конструктор перемещения не будет неявно определен как удаленный.
и / 11:
Неявно объявленный конструктор копирования / перемещения является
inline public
член своего класса. Дефолтная копия /
переместить конструктор для классаX
определяется как удаленный (8.4.3), еслиX
имеет:
- […]
- для конструктора копирования — нестатический член данных ссылочного типа rvalue или
- для конструктора перемещения — нестатический член данных или прямой или виртуальный базовый класс с типом, который
не имеет конструктора перемещения и не является легко копируемым.
Как with_copy
является не тривиально копируемый, foo
буду иметь нет Конструктор перемещения (он будет определен как удаленный, поэтому не будет объявлен неявно).
C ++ 1y, точнее github repo commit e31867c0 от 2013-11-12; включения DR1402:
/ 9:
Если определение класса
X
явно не объявляет ход
конструктор, один будет неявно объявлен как дефолт, если и только
если
X
не имеет объявленного пользователем конструктора копирования,X
не имеет заявленного пользователем оператора копирования,X
не имеет объявленного пользователем оператора назначения перемещения, иX
не имеет объявленного пользователем деструктора.
и / 11:
Неявно объявленный конструктор копирования / перемещения является
inline public
член своего класса. По умолчанию конструктор копирования / перемещения для классаX
определяется как удаленный (8.4.3), еслиX
имеет:
- […]
- для конструктора копирования — нестатический член данных ссылочного типа rvalue.
Конструктор перемещения по умолчанию, который определен как удаленный, игнорируется
разрешение перегрузки (13,3, 13,4).
Вот, foo
будет иметь движение-конструктор.
Я не совсем уверен, что вы проверяли, но это foo
безусловно, и двигаться назначаемым и двигаться конструктивно. Следует признать, что это ничего не говорит о конструкторе перемещения или доступном назначении перемещения, просто работает эта конструкция или назначение из rvalue. И то и другое лязг (лямка версии 3.5 (багажник 196718)) и НКУ (gcc версия 4.9.0 20131031 (экспериментальная) (GCC)) согласен с этой оценкой. Это полный источник, который я попробовал:
#include <iostream>
#include <type_traits>
#include <memory>
struct with_copy {
with_copy() = default;
with_copy(with_copy const&) {}
with_copy& operator=(with_copy const&) { return *this; }
};
struct foo {
with_copy c;
std::unique_ptr<int> p;
};
int main()
{
std::cout << "move constructible: "<< std::is_move_constructible<foo>::value << '\n';
std::cout << "move assignable: "<< std::is_move_assignable<foo>::value << '\n';
foo f0;
foo f1 = std::move(f0);
f0 = std::move(f1);
}