6

I have read many articles about move constructor (even on stack) but i didn't find anywhere an exact explanation about how this works (how is transfer pointer to a temporary object and saved if this temporary variable and its address will be destroy when meet ")" ).

Here is a simple example

#include <iostream>
#include <vector>
using namespace std;
class boVector {
private:
    int size;
public:
    boVector() {};
    boVector(const boVector& rhs) { cout << "copy Ctor." << endl; }
    boVector(boVector&& rhs) { cout << "move Ctor." << endl; }
};

void foo(boVector v) {}
boVector createBoVector() { return boVector(); }

int main()
{
    //copy
    boVector reausable = createBoVector();
    foo(reausable);
    //move
    foo(std::move(createBoVector()));
    return 0;
}

All say that a move Ctor is a shallow copy copy or just a pointer assignment. But how can i initiate my object with a pointer to a temporary object (when this object will be destroy my object will point to an unknown address and this is not valid from my point of view).

Is not right to initiate a variable with a pointer address that will no longer exist after he meet ")".

Please if can somebody explain me how looks this temporary variable in memory and how is possible to assigned the address of temporary object to my current one and this operation to be a valid one.

einpoklum
  • 118,144
  • 57
  • 340
  • 684

2 Answers2

10

A "move constructor" is nothing magical - it is a constructor that takes an rvalue reference.

Rvalue references bind to temporary object, and have the "meaning" of something that's about to expire and that won't be accessed later on in the program: this enables developers to implement moves for resource-holding classes in terms of pointer swaps or similarly fast operations.

Your boVector class cannot really take any advantage from move semantics, as it just stores an int and doesn't hold any resource. Moving an int is as fast as copying one.


In the

foo(std::move(createBoVector()));

expression, std::move is redundant as createBoVector() is already an rvalue.


Consider:

foo(createBoVector());

This will invoke boVector(boVector&&) as it's a better match than boVector(const boVector&).

The instance created by createBoVector() will live for the full duration of the expression - this means that the rvalue reference will be pointing to a valid object for the duration of boVector(boVector&&).

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • What i can't understand is how can i bind a temporary value to my object if this will be destroy. For example boVector(boVector&& size) temporary object start to exist with "(" and end his existence with ")". If in my move Ctor i say something like **this.m_size = size**. After the end of the Ctor **size** dosen't exist anymore so also m_size should be empty. –  Jan 17 '18 at 13:57
  • @Adrian what will be destroyed is the *moved-from* object, the temporary (think of it as an empty object after being moved-from), and **not** the *moved-to* object. – JFMR Jan 17 '18 at 14:06
  • @Adrian `this->m_size` is not a reference. Therefore `this->m_size = size` assignment makes a copy. After the copy, whatever happens to the object that was copied from has no effect on `m_size` because it is a separate object. – eerorika Jan 17 '18 at 14:13
  • So here the move Ctor is acting like a copy ctor? When i think at move i am thinking for example if i see a watch..i like it so i take it. What is the point to take it if the watch it will destroy itself. When i am thinking at copy ctor..ok i see the watch i like it so i make my own watch after yours but without auto destroying mechanism. –  Jan 17 '18 at 14:22
  • @Adrian Think of moving as moving the contents of the object, not the object itself. In a sense, the original object isn't moved per se, but disappears. (A more similar situation would be "what is the point in taking the watch from the table if it's not going to be on the table any more", which I think you'll agree is a strange thing to ask yourself.) – molbdnilo Jan 17 '18 at 15:03
  • @molbdnilo maybe here is my problem. If i think to move the content and not the object itself then it will be copy constructed because i can't assign to my abject an address, i need to copy all the content. When i am thinking on a move Ctor i am thinking at some address that is assigned to my object in order to avoid recopying. I am right? –  Jan 17 '18 at 15:12
  • @Adrian You shouldn't be thinking about addresses at all - no objects are *physically* moved. The only difference between the move constructor and the copy constructor is that the move constructor's argument will be destroyed when you're finished with it - that's why you're allowed to "steal" its data and empty it (but you don't have to). Both objects remain in the same place, only their contents change. – molbdnilo Jan 17 '18 at 15:23
  • @molbdnilo Then what is the point of the move Ctor if in the end i need to copy the content of the temporary object, and i can't make my object just point to the new temporary one? How is this more efficient than copy ctor?:( Thanks for your patience. –  Jan 17 '18 at 15:31
  • @Adrian Consider an object with a pointer to an array with a million strings. If you copy it, you need to copy a million strings, and the other object will then free its memory, destroying a million strings with it. If you move it, you just copy the pointer and set the other object's pointer to the null pointer. Now you've copied only one pointer and destroyed nothing. – molbdnilo Jan 17 '18 at 15:36
  • I understand. The pointer inside the object is valid because is still pointing to a valid array (is not deleted). After this we only need to set the temporary object to null. Now i understand what is the idea. Thank you very much @molbdnilo –  Jan 17 '18 at 15:48
2

All say that a move Ctor is a shallow copy copy or just a pointer assignment.

Not all say that, as it is not true. A move constructor is what you define it to be. In your example, your move ctor does something else entirely. The point of a move ctor - as opposed to a copy ctor - is that you know that the other object is about to be destroyed, so you can cannibalize, or move, its resources.

A move constructor may make a "shallow copy", although that term is colloquial rather than well-defined in C++. "Just a pointer assignment" - perhaps, possibly, sometimes.

But how can i initiate my object with a pointer to a temporary object (when this object will be destroy my object will point to an unknown address and this is not valid from my point of view).

You don't (usually) initialize an object of type T with a pointer of type T*, per se. You can assign my_t = *my_t_ptr, or if you know you can "cannibalize" the T which my_t_ptr is pointing to, since it will soon be deleted, then you can assign my_t = std::move(*my_t_ptr).

Can you give me a more relevant example [of a meaningful difference between a move constructor and a copy constructor]...?

The "classical" example is when your T is constructed by allocating some space on the heap. When you copy-construct one T from another, you have no choice but to allocate a second stretch of memory; when you move-construct a T, you can :1. copy the pointer from the existing T to the T under construction. 2. set the existing T's member pointer to nullptr. In this case you only ever use one T's worth of stack space.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • @Adrian: In your case - no difference between move and copy ctor. And indeed, a "shallow copying" of an integer, or a structure-with-an-integer, is the same as a "deep" copy. Also, in your example, no temporary objects will be used at all. – einpoklum Jan 17 '18 at 14:43
  • can you give me a more relevant example, that we can speek about? –  Jan 17 '18 at 15:08