Подтвердить что ты не робот

Конструктор перемещения С++ 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.
Является ли это правильной реализацией конструктора перемещения?

4b9b3361

Ответ 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;