0

I am having trouble understanding c++ move semantics. Suppose I want to return a large object from a method. In order to make this operation efficient, I use a move constructor for the large object class. I call a method to obtain a large object and pass it to another method that will process it.

processLargeObject(getLargeObject());

I write a method getLargeObject() where I create a large object. If I create the object without the new operator, I am given to understand that the storage is allocated on the stack. In a case where I know the size of the object in advance and I represent it in an array, this large object can be defined as double foo[1000000000];. Now inside the move constructor, if I say

foo = other.foo;

then the moved object will still reside on the stack and can be overwritten as the stack expands.

So this must not be how a move constructor is used. Should a move constructor be used only for moving objects that reside on the heap?

Praetorian
  • 106,671
  • 19
  • 240
  • 328
AggieMan
  • 84
  • 8
  • `foo = other.foo;` will not compile if `foo` is an array of doubles. And how exactly would you move a plain array of doubles anyway? – Praetorian Aug 18 '16 at 23:50
  • Does that mean that I have to loop through the array and create a copy? – AggieMan Aug 18 '16 at 23:52
  • Have you tried declaring and using an object that has a billion doubles in a plain array in it? Seems like a good way to overflow your stack. You should be using a `vector` and then moving would actually make sense. – Praetorian Aug 18 '16 at 23:56
  • I think the way a vector is implemented, it will be moved because of its move constructor. I'm just trying to understand move semantics. – AggieMan Aug 18 '16 at 23:58
  • Isn't moving the contents of that array what you want? `vector` will do that for you. Read [this](http://stackoverflow.com/q/3106110/241631), it has some good answers about move semantics. – Praetorian Aug 19 '16 at 00:00
  • My aim is to understand the move constructor and move semantics. I'm a c++ newb. I am given to understand that if I don't use the new operator, then storage is allocated on the stack. Now if a method in which I allocate storage for an object throws and exception, the destructor will still be called when the method goes out of scope. So I'm told that if I don't use the new operator, the code will be less likely to leak memory. However if I use this way of programming, I'm not sure how to use a move constructor to return an object from a method. – AggieMan Aug 19 '16 at 00:08
  • Possible duplicate of [What are move semantics?](http://stackoverflow.com/q/3106110/3425536) – Emil Laine Aug 19 '16 at 00:17

1 Answers1

2

How does a move constructor work?

A move constructor should do a shallow copy - as opposed to a deep copy that a copy constructor should do. In addition to doing a shallow copy, the move constructor "steals" any resources (such as an external memory buffer, for example the buffer owned by std::vector) pointed by the moved-from object.

In order to make this operation efficient, I use a move constructor for the large object class.

Pedantically speaking, largeness of the object itself does not make the move any more efficient than a copy. A move is efficient when the object points to some large resource that can be "stolen". If you meant that such external resource is what makes the object "large", then fair enough.

Should a move constructor be used only for moving objects that reside on the heap?

Regardless of where an object is stored - be it automatic, dynamic or static, it can be moved from. As long as the type is movable.

this large object can be defined as double foo[1000000000];

That is a good example of a very large object, that doesn't point to any external resource that could be stolen. Moving an array of doubles is exactly the same thing as copying it.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Thanks. I got this part. What I don't get is, does the moved object need to reside on the heap? – AggieMan Aug 19 '16 at 00:01
  • For the move constructor to give a significant benefit, most of the data should be stored in data on the heap referred to by pointers in the object. (So, a `std::array` is normally just as expensive to move-construct as to copy-construct; but a `std::vector` with 1000000 elements is very fast to move-construct.) – Daniel Schepler Aug 19 '16 at 00:08
  • Thanks!!! Makes sense to me now. So is the following a good summary of good programming practice: Create objects without new operator so that chances of a memory leak are minimized. The object created can hold memory on the heap. Code the destructor so that heap memory is released. This way the memory is guaranteed to be returned. Code a move constructor in such a way that the moved object points to the location of the old object and make the old object point to a nullptr. – AggieMan Aug 19 '16 at 00:12
  • @AggieMan use `std::unique_ptr` or `std::shared_ptr` and `std::vector` rather than managing memory yourself. If your data is fixed size you can always use `std::unique_ptr>`. Creating an object with `double foo[1000000000]` as a member on the stack is just asking for trouble. Stack is limited. – kfsone Aug 19 '16 at 00:39