10

I know this question might seem very very basic. But I just can't find anywhere an example of a move constructor with no pointers.

I have a class that holds a vector object variable. Not a pointer to one. So my question: Does this mean that I have no need in a move constructor? Or is my implementation wrong and I should be using a pointer to a vector and then use a move constructor?

Thank you

wjk2a1
  • 776
  • 1
  • 7
  • 16
  • 2
    You should still have a move constructor, since `std::vector` can benefit from moving. The compiler-generated one (memberwise move) should be good enough. – T.C. Sep 09 '14 at 07:25
  • I believe it's called *Copy Constructor*, not *Move Constructor*. – barak manos Sep 09 '14 at 07:25
  • 1
    @AlexFarber: Default copy-constructor is good enough if there are no member pointers (as mentioned above by T.C.). – barak manos Sep 09 '14 at 07:27
  • Also there is a special [swap()](http://www.cplusplus.com/reference/vector/vector/swap/) method for very fast transfering of data from one vector to another one. – Ilya Sep 09 '14 at 07:30
  • 4
    @barakmanos: No, they're two separate concepts. Perhaps you're not familiar with C++11's [move semantics](http://stackoverflow.com/questions/3106110)? – Mike Seymour Sep 09 '14 at 07:30
  • @T.C.: But wouldn't it be empty without having a pointer to swap? – wjk2a1 Sep 09 '14 at 07:38
  • @MikeSeymour: Interesting, thanks. – barak manos Sep 09 '14 at 07:39

3 Answers3

15

If your class contains movable objects (such as a vector), then just let the compiler generate the implicit move operations. They will do the right thing, moving each subobject.

You'll only need to write your own if you're juggling raw pointers to dynamic objects, or other unmanaged resource handles, yourself. The best approach is to have a correctly copyable/movable object (such as a container, smart pointer, or other RAII class) to manage each of these; then a complex object built by composing these will implicitly have the correct copy/move semantics.

(As noted in the comments: if your class declares its own destructor, or copy operations, then it won't get implicit move operations; you'll need to define your own. But if you follow the advice above, composing it from correctly managed types that don't need any special handling, then you shouldn't need to declare any of these things.)

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • So letting the compiler generate it implicitley is still efficient enough? Or should I use pointers? – wjk2a1 Sep 09 '14 at 07:37
  • 3
    @wjk2a1: Using the implicit version will probably be more efficient than introducing an extra level of indirection, and certainly simpler and less error prone. If you really need to worry about the cost of individual pointer updates, then you'll need to measure the costs of both approaches yourself. – Mike Seymour Sep 09 '14 at 07:40
  • 3
    note that if your class has a user-declared destructor then there is no implicitly-generated move constructor; so to ensure that one exists, you could explicitly define it as `default`. – M.M Sep 09 '14 at 07:43
  • 1
    @MattMcNabb: Indeed, that's worth noting. But you shouldn't need a special destructor unless you're writing your own resource management class, or doing something weird; in which case, you probably also need special move semantics. – Mike Seymour Sep 09 '14 at 07:51
3

Move constructor follows similar guidelines as copy constructors. It is required when your class holds members by pointer or other fragile data fields (sockets, db connections etc), so that automatically generated one would possibly mess up the memory layout by deleting the same object twice. So if you don't have any pointer fields, you don't have to write move constructor.

lisu
  • 2,213
  • 14
  • 22
1

The default move constructor and move asignment generated by the compiler will call move constructor/asignment for each member of the class.

If your class has only raw members, "char * buffer" for example, you have to write your own move operations.

If your class has only "managed members", "vector" for example, default move operations for you class will be ok because it delegates the operation to each member.

If your class has "managed members" mixed with "raw members", vector and int* for example, your movement operations will have to do the manual move of raw resources and call move operations for managed objects:

class MyObject {
public:
    // ...


    MyObject(MyObject&& other) : vector1(std::move(other.vector1)) {
        // We use vector's move constructor ^

        // and then move ourself the char* buffer
        buffer1 = other.buffer1;
        other.buffer1 = nullptr;        
    }

    MyObject& operator=(MyObject&& other) {
        // We use vector's move asignment operator
        vector1= std::move(other.vector1);

        // and then move ourself the char* buffer
        std::swap(buffer1,other.buffer1);
        return *this;
    }

    //...
private:
    vector<char> vector1;
    char * buffer1;
};

std::move(other.vector1) is needed because inside that function other.vector1 is an lvalue. We have to tell the compiler we will not use vector1 value later in the function code so it's value can be moved.

davidaf
  • 351
  • 1
  • 4