2

I have read the below post which gives a very good insight into move semantics:

Can someone please explain move semantics to me?

but I am still fail to understand following things regarding move semantics -

  1. Does copy elision and RVO would still work for classes without move constructors?

  2. Even if our classes doesn't have move constructors, but STL containers has one. For operation like

std::vector<MyClass> vt = CreateMyClassVector();

and to perform operations like sorting etc. Why can't STL internally leverage move semantics to improve such operations internally using operations like copy elision or RVO which doesn't require move constructors?

3. Do we get benefited by move semantics in below case -

std::vector< int > vt1(1000000, 5); // Create and initialize 1 million entries with value 5

std::vector< int > vt2(std::move(vt1)); // move vt1 to vt2

as integer is a primitive type, moving integer elements will not offer any advantage. or here after move operation vt2 simply points to vt1 memory in heap and vt1 is set to null. what is actually happening? If latter is the case then even point 2 holds that we may not need move constructor for our classes.

4. When a push_back() is called using std::move on lvalue for e.g :

    std::vector<MyClass> vt;

    for(int i=0; i<10; ++i)
    {
        vt.push_back(MyClass());
    }

    MyClass obj;

    vt.push_back(std::move(obj));

now as vector has contiguous memory allocation, and obj is defined somewhere else in memory how would move semantics move the obj memory to vector vt contiguous memory region, wouldn't moving memory in this case is as good as copying memory, how does move justifies vectors contiguous memory requirements by simply moving a pointer pointing to a memory in different region of a heap.?

Thanks for explanation in advance!

[Originally posted as Move semantics clarification but now as the context is changed a bit posting it as new question shall delete the old one ASAP.]

Community
  • 1
  • 1
Goku
  • 43
  • 6

2 Answers2

2

Does copy elision and RVO would still work for classes without move constructors?

Yes, RVO still kicks in. Actually, the compiler is expected to pick:

  • RVO (if possible)
  • Move construction (if possible)
  • Copy construction (last resort)

Why can't STL internally leverage move semantics to improve such operations internally using operations like copy elision or RVO which doesn't require move constructors?

The STL containers are movable, regardless of the types stored within. However, operations on the objects in the container require the object cooperation, and as such sort (for example) may only move objects if those objects are movable.

Do we get benefited by move semantics in below case [...] as integer is a primitive type ?

Yes, you do, because containers are movable regardless of their content. As you deduced, st2 will steal the memory from st1. The state of st1 after the move is unspecified though, so I cannot guarantee its storage will have been nullified.

When a push_back() is called using std::move on lvalue [what happens] ?

The move constructor of the type of the lvalue is called, typically this involves a bitwise copy of the original into the destination, and then a nullification of the original.

In general, the cost of a move constructor is proportional to sizeof(object); for example, sizeof(std::string) is stable regardless of how many characters the std::string has, because in effect those characters are stored on the heap (at least when there is a sufficient number of them) and thus only the pointer to the heap storage is moved around (plus some metadata).

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • Thanks, You mentioned as containers are movable vector st2 will steal the memory from st1, do you mean st2 will now point to st1 object memory layout(just like RVO) and need not move each integer member of st1. Then in latter case of string object why does it need to copy size and pointer to buffer only rather it can directly point to object memory layout of string object and set original object to null somewhat like how RVO works it just creates a new reference to temporary object. – Goku Feb 01 '13 at 10:22
  • @Goku: 1/ Vector: yes, the pointer-to-date/size/capacity are *transferred* from `st1` to `st2` somehow. 2/ String: the same occurs, pointer-to-date/size/capacity are *transferred* from one string to another. – Matthieu M. Feb 01 '13 at 10:39
1
  1. Yes.
  2. They do, as far as possible.
  3. Yes. std::vector has a move constructor that avoids copying all the elements.
  4. It is still in contiguous.

e.g.

struct MyClass
{         
     MyClass(MyClass&& other) 
         : xs(other.xs), size(other.size)
     {
          other.xs = nullptr;
     }

     MyClass(const MyClass& other) 
       : xs(new int[other.size]), size(other.size)
     { 
         memcpy(xs, other.xs, size);
     }

     ~MyClass() 
     {               
         delete[] xs;
     }

     int* xs;
     int size;
}

With a move constructor only xs and size needs to be copied into the vector (for contiguous memory), however we do not need the perform memory allocation and memcpy as in the copy constructor.

ronag
  • 49,529
  • 25
  • 126
  • 221
  • Thanks @ronag : Does the standard says anything about point 2. I have not really understood your comment for point 3, yes vector does have move constructor but here does it do member wise move(which is equivalent to copy for integers case) for all elements or simply make vector vt2 point to heap allocation of vector v1. and for point 4 without memory allocation for element of vector how would you copy xs to it, if you just copy pointer then it will point to memory region which is not in vectors contiguous memory – Goku Jan 31 '13 at 06:50
  • 2. The STl uses RVO and similar optimizations the same way as any other code. 3. It does not do a memberwise move, it works similarly as my MyClass example. 4. Only MyClass (i.e. it's members xs and size) need to be contigious in memory, whether MyClass has some pointer pointing somewhere else is irrelevant. – ronag Jan 31 '13 at 07:45