DanDan
DanDan

Reputation: 10562

Move constructor does not implicitly work for member variables?

Why doesn't this: (vs2010) move the vector within the class?

#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;
}

Does this mean every class that uses std::vector (and other moveable classes) should have an explicit move constructor and assignment?

Upvotes: 3

Views: 1357

Answers (4)

Howard Hinnant
Howard Hinnant

Reputation: 218830

In addition to the good answers already given regarding the lateness of these rules compared to when vs2010 shipped,

The rules for an implicitly generated move constructor are:

If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

  • X does not have a user-declared copy constructor,
  • X does not have a user-declared copy assignment operator,
  • X does not have a user-declared move assignment operator,
  • X does not have a user-declared destructor, and
  • the move constructor would not be implicitly defined as deleted.

The rules for implicitly generated move assignment operators follows the pattern above.

The rules for when a copy constructor is implicitly generated have changed slightly!

If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.

And similarly for the copy assignment operator:

If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor.

Bottom line: The rule of 3 is now the rule of 5. You can either ignore all 5 (if the default behavior works for you), or you need to think about (and likely define) all 5:

  1. copy constructor
  2. copy assignment
  3. move constructor
  4. move assignment
  5. destructor

Upvotes: 9

Anthony Williams
Anthony Williams

Reputation: 68611

With a fully-conforming C++0x compiler, your class will have an implicit move constructor that moves the members, as well as the implicit copy constructor. In this example, the implicit move constructor will therefore be used.

However, MSVC2010 came out before this rule was agreed on by the committee, so you must write a move constructor explicitly. You will then need to define the default constructor and copy constructor as well, and probably ought to define the move-assignment and copy-assignment too for good measure:

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;
    }

};

Upvotes: 7

Puppy
Puppy

Reputation: 146940

VS2010 does not have implicit move constructors. You will have to explicitly write one.

Upvotes: 1

Bo Persson
Bo Persson

Reputation: 92271

The MoveTest class doesn't have a move constructor, so it used the default copy constructor.

A copy constructor copies the member elements. :-)

There might be cases where a C++11 conformat compiler would generate a default move constructor, but I'm not sure where the final rules ended up (there were very late changes). VS2010 is too old to know about that as well.

Upvotes: 2

Related Questions