5

When I read examples about move semantics and rvalue references, they're using the advantages of rvalue references and move semantics around big objects which wrap pointers e.g. 1 2

For example, they just copy the pointer which is inside the moving object and set it to nullptr. (Move/Swap)

My question is, Do move semantics have any advantage (performance) for objects which don't have pointers but they're big?

class BigClass
{
   int data[BIG_SIZE];
   int a01;
   .
   .
   . many members
   .
   .
   int z99;

public:

   move constructor ?!
};
Community
  • 1
  • 1
masoud
  • 55,379
  • 16
  • 141
  • 208
  • Yes. After the move operation the _other_ object is (or should be) reset to a _default_ state. – Captain Obvlious May 24 '13 at 13:58
  • No, there's not really an advantage as far as direct value members are concerned. – Kerrek SB May 24 '13 at 14:01
  • 1
    @CaptainObvlious Why waste time on changing the other object to the default state? The standard doesn't specify in which state the other object should be in after the move operation. Seeing as the other object is (ostensibly) a temporary, the only reason I can see for changing it is if we want to leverage its destructor to clean up resources from `*this` (which is usually done by swapping the other object and `this`). – Agentlien May 24 '13 at 14:03
  • @Agentlien Not entirely true. The standard does say that the object must be left in a destructable state. – Andre Kostur May 24 '13 at 14:19
  • @AndreKostur That's true, of course. After thinking more on it, I'd say minimal resetting is good in a move constructors where it is necessary to ensure that the destructor does the right thing and does not free resources whose ownership should have been moved to the target instance. In move assignment, you need to swap such members. But for members which are not owning (smart) pointers or similar resource handlers, resetting still seems superfluous. – Agentlien May 24 '13 at 14:27
  • @Agentlien Resetting the object state could mean defaulting a single member variable. It does not necessarily apply to all data. – Captain Obvlious May 24 '13 at 14:35
  • @CaptainObvlious Yes, that's true. I'm just saying that you don't really need to reset all members which are part of the (publicly visible) state. Only those that affect how the destructor is run. I can understand if you'd still recommend doing so for clarity and consistency. Personally however, I find it overkill. It won't make a difference unless you move from an object and then keep using the object moved from anyway. But if you do that, I'd say you're misusing move semantics. – Agentlien May 24 '13 at 14:39

2 Answers2

10

Do move semantics have any advantage for objects which don't have pointers but they're big?

It will not have any advantage in terms of performance, because you won't be able to quickly "steal the guts" of the object being moved from, as you've noticed.

However, from the purely logical perspective, the semantics of your class may be such that your object is not supposed to be copyable, and therefore a copy-constructor cannot/should not be provided.

For instance, the internals of a unique_ptr are not anything that could be moved any faster than it could be copied (it's a zero-overhead wrapper over a raw pointer), but semantic constraints make it impossible to copy a unique_ptr. In this context, move semantics is all about keeping the invariant that only one unique_ptr pointing to a certain object must exist at a certain time in your program.

Therefore, the move constructor (or move assignment operator) of the unique_ptr also has to reset the pointer being moved from to keep the invariant.

Your class may be something completely different from a unique_ptr, and perhaps considerably heavier, but there may still be semantic constraints that make it non-copyable. In that case, move semantics can be exploited to enforce the correct invariants.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Good point about non-copyable classes. I've asked myself this question before, and this is precisely the answer I wasn't able to find. – Agentlien May 24 '13 at 14:11
  • @Agentlien: Glad you found it helpful :) – Andy Prowl May 24 '13 at 14:11
  • So does it better to make my `BigClass` a composition of smart pointers and STLs to have move semantic advantages? – masoud May 24 '13 at 14:15
  • @MM.: You could adopt the pimpl idiom, yes, that would make moves at the same time exception-safe and fast - but would require you to provide a lot of wrapper functions that do nothing but forwarding, and would the make memory access pattern more sparse. It's an engineering compromise, as always. Whether you should adopt it or not depends on your requirements. Also notice, that "STLs" is a wrong term. You probably meant "types from the C++ Standard Library" :) – Andy Prowl May 24 '13 at 14:19
1

Since each object retains a copy of all its data and there is no pointer to transfer, it's impossible to do a shallow copy, as you noted. It might make sense, depending on the situation, to set the other object back to its default state, but that's the only possible difference you'd have between the move constructor and the copy constructor.

Matt Kline
  • 10,149
  • 7
  • 50
  • 87
  • Since when? A move constructor isn't required to set the object it is moving from to any particular state afaik – Andrew Tomazos May 24 '13 at 14:00
  • No. It need not. The moved from object should be destructible and assignable, but it need not be reset (although that might be a good practice). As an extreme example, moving from an `int` is exactly like copying: the source retains its state. – Matthieu M. May 24 '13 at 14:00
  • Why would it be good practice to set the moved-from object to a default state? – Andrew Tomazos May 24 '13 at 14:03
  • To convey that its state has been transferred to the moved-to object. One might raise a point that this is a waste of time, but if that is the case, why have a move constructor in this situation at all? Unless the move constructor does something different than the copy constructor, there's no point in having it. – Matt Kline May 24 '13 at 14:05
  • @slavik262 Which is exactly what Andy Prowl's answer deals with and answers very nicely. I'm personally of the opinion that if you steal resources, you probably want to swap them between the two. This would be a reset in move constructor (and can be implemented as such), and in move assignment it lets the other object's destructor takes care of resources currently held by the object you move into. – Agentlien May 24 '13 at 14:16
  • @Agentlien - Andy said what I was trying to get at much more concisely. – Matt Kline May 24 '13 at 14:54
  • @slavik262 He tends to do that. – Agentlien May 24 '13 at 14:55