Конструктор Move неявно работает для переменных-членов? - PullRequest
3 голосов
/ 12 мая 2011

Почему это не: (vs2010) перемещать вектор внутри класса?

#include <vector>

class MoveTest
{
public:
    std::vector<int> m_things;
};

int _tmain(int argc, _TCHAR* argv[])
{
    MoveTest m;
    m.m_things.push_back(12);

    MoveTest m2 = std::move(m);
    // std::vector has been copied, not moved

    return 0;
}

Означает ли это, что каждый класс, использующий std :: vector (и другие подвижные классы), должен иметь явное перемещениеконструктор и присваивание?

Ответы [ 4 ]

9 голосов
/ 12 мая 2011

В дополнение к уже полученным хорошим ответам относительно запоздалости этих правил по сравнению с тем, когда была выпущена версия vs2010,

Правила для неявно сгенерированного конструктора перемещения:

Еслиопределение класса X явно не объявляет конструктор перемещения, он будет неявно объявлен как дефолтный, если и только если

  • X не имеет объявленного пользователем конструктора копирования,
  • X не имеет объявленного пользователем оператора назначения копирования,
  • X не имеет объявленного пользователем оператора назначения перемещения,
  • X не имеет объявленного пользователем деструктора и
  • конструктор перемещения не будет неявно определен как удаленный.

Правила для неявно сгенерированных операторов присваивания перемещения следуют приведенному выше шаблону.

Правила для случая, когдаконструктор копирования генерируется неявно изменилось немного!

Если определение класса не объявляет копию явноконструктор, один объявлен неявно.Если определение класса объявляет конструктор перемещения или оператор присваивания перемещения, неявно объявленный конструктор копирования определяется как удаленный;в противном случае он определяется как дефолтный (8.4).Последний случай считается устаревшим, если в классе есть объявленный пользователем оператор присвоения копии или объявленный пользователем деструктор.

И аналогично для оператора присвоения копии:

Еслиопределение класса не объявляет явно оператор присваивания, один объявляется неявно.Если определение класса объявляет конструктор перемещения или оператор присваивания перемещения, неявно объявленный оператор присваивания копии определяется как удаленный;в противном случае он определяется как дефолтный (8.4).Последний случай считается устаревшим, если в классе есть пользовательский конструктор копирования или деструктор, объявленный пользователем.

Итог: правило 3 теперь является правилом 5. Вы можете либо игнорировать все5 (если поведение по умолчанию работает для вас), или вам нужно продумать (и, вероятно, определить) все 5:

  1. конструктор копирования
  2. копирование назначения
  3. переместить конструктор
  4. переместить назначение
  5. деструктор
7 голосов
/ 12 мая 2011

С полностью соответствующим компилятором C ++ 0x ваш класс будет иметь неявный конструктор перемещения, который перемещает члены, а также неявный конструктор копирования.В этом примере будет использоваться неявный конструктор перемещения.

Однако MSVC2010 вышел до того, как это правило было согласовано комитетом, поэтому вы должны явно написать конструктор перемещения.Затем вам нужно будет также определить конструктор по умолчанию и конструктор копирования, и, вероятно, для правильной меры следует также определить перемещение-назначение и копирование-назначение:

class MoveTest
{
public:
    std::vector<int> m_things;

    MoveTest()
    {}

    MoveTest(MoveTest&& other):
        m_things(std::move(other.m_things))
    {}

    MoveTest(MoveTest const& other):
        m_things(other.m_things)
    {}

    MoveTest& operator=(MoveTest&& other)
    {
        MoveTest temp(std::move(other));
        std::swap(*this,temp);
        return *this;
    }

    MoveTest& operator=(MoveTest const& other)
    {
        if(&other!=this)
        {
            MoveTest temp(other);
            std::swap(*this,temp);
        }
        return *this;
    }

};
2 голосов
/ 12 мая 2011

Класс MoveTest не имеет конструктора перемещения, поэтому он использовал конструктор копирования по умолчанию.

Конструктор копирования копирует элементы-члены. : -)

Могут быть случаи, когда компилятор, соответствующий C ++ 11, сгенерирует конструктор перемещения по умолчанию, но я не уверен, где окончательные правила закончились (были очень поздние изменения). VS2010 слишком стар, чтобы знать об этом.

1 голос
/ 12 мая 2011

VS2010 не имеет неявных конструкторов перемещения. Вам придется явно написать один.

...