Конструктор перемещения С++ 11
Каким будет правильный способ реализации конструктора перемещения с учетом следующего класса:
class C {
public:
C();
C(C&& c);
private:
std::string string;
}
Конечно, идея состоит в том, чтобы избежать копирования string
или выключения его дважды.
Давайте предположим, что основной пример является просто для ясности, и мне нужен конструктор перемещения.
Я пробовал:
C::C(C&& c) {
//move ctor
string = std::move(c.string);
}
и
C::C(C&& c) : string(std::move(c.string)) {
//move ctor
}
Оба компилируют штраф на gcc 4.8 и работают нормально. Кажется, что вариант A - правильное поведение, string
копируется, а не перемещается с опцией B.
Является ли это правильной реализацией конструктора перемещения?
Ответы
Ответ 1
Так как std::string
сам имеет move-ctor, неявно определенный move-ctor для C
позаботится о правильной операции перемещения. Вы не можете определить это самостоятельно. Однако, если у вас есть другой член данных и, в частности,
12.8 Копирование и перемещение объектов класса
12 Неявно объявленный конструктор копирования/перемещения является встроенным общедоступным член его класса. По умолчанию конструктор copy/move для класса X определяется как удаленный (8.4.3), если X имеет:
- вариантный элемент с нетривиальный соответствующий конструктор и X - объединенный класс,
- a нестатический элемент данных класса M (или его массив), который не может скопировать/перемещать, поскольку разрешение перегрузки (13.3), применимое к Ms соответствующий конструктор, приводит к двусмысленности или функции, которая удаляется или недоступен из конструктора, установленного по умолчанию, или
- a прямой или виртуальный базовый класс B, который нельзя скопировать или переместить, потому что (13.3), применительно к Bs, соответствующему конструктор, приводит к двусмысленности или функции, которая удалена или недоступный из конструктора, установленного по умолчанию, или
- за ход конструктор, нестатический член данных или прямой или виртуальный базовый класс с типом, который не имеет конструктора перемещения и не является тривиальным копируемый.
13 Конструктор копирования/перемещения для класса X тривиален, если он ни пользователем, ни удаленным, и если
- класс X не имеет виртуальных функций (10.3) и виртуальных базовых классов (10.1) и функций (10.3) и виртуальных базовых классов (10.1) и
- конструктор, выбранный для копирования/перемещения каждого подобъекта прямого базового класса, является тривиальным и
- для каждого нестатического элемента данных X, который имеет класс тип (или его массив), конструктор, выбранный для копирования/перемещения этого член тривиален; в противном случае конструктор copy/move является нетривиальным.
вы можете захотеть реализовать свой собственный move-ctor.
Если вам нужен move-ctor, предпочтите синтаксис списка инициализаторов. Всегда! В противном случае вы можете создать конструкцию по умолчанию для одного объекта, не упомянутого в списке инициализаторов (это то, что вы вынуждены для объектов-членов только с нестандартными ctors).
Ответ 2
Оба варианта будут перемещать строку. Второй вариант должен быть предпочтительным, потому что он не будет по умолчанию строить пустую строку, просто чтобы переместить ее потом.
Проверьте свой тестовый файл, а затем список компиляторов bugzilla. Вам необходимо отследить вызовы как для string::operator=(string&&)
(1-й случай), так и для string::string(string&&)
(2-й случай), если вы хотите, чтобы оба случая они двигались.
Ответ 3
Оба Конструктора должны работать. Таким образом, оба являются правильными конструкторами перемещения. Второй может быть более эффективным, так как первый по умолчанию создает string
только для его назначения, а второй просто перемещает его конструкцию и поэтому должен быть более эффективным. Если второй из них менее эффективен, я бы заподозрил ошибку компилятора (помните, что поддержка С++ 11 по-прежнему не завершена для текущих компиляторов) или некорректная тестовая методология (как именно вы проверяете копию и перемещение, и уверены, что конструктор перемещения а не присваивание op вызывается в обоих случаях?).
Конечно, если возможно, вы можете просто позволить компилятору сгенерировать ваш конструктор с помощью C(C&&) = default;
.
Ответ 4
Здесь нет необходимости реализовывать конструктор перемещения, поскольку вам не нужно вручную управлять памятью. Перемещение конструкторов полезно только при ручном использовании динамических массивов в вашем классе.
Вы все еще можете явно создать компилятор конструктора перемещения по умолчанию, хотя он уже должен был быть выполнен, даже если вы не запрашиваете его:
C(C&& c) = default;