9

How do I efficiently move a class with a large set of POD members? Example:

struct{
    int a1;
    int a2;
    int a3;
    ...
    ...
    ...
};

By 'move' I mean that the behavior is similar to the move semantic (std::move).

ggg
  • 1,857
  • 2
  • 21
  • 33
  • 3
    I don't think it gets any faster than a simple assignment. – Mysticial Jul 21 '12 at 02:36
  • If it's possible for you to store all of these in an array, dynamically allocate it and steal the pointer. Otherwise, assignment is probably your best bet. – chris Jul 21 '12 at 03:02

4 Answers4

18

PODs don't move, they just copy. Because there's no indirection. So just use an ordinary assignment, and ask the compiler to optimize for whatever efficiency you have in mind. Remember to measure, systematically, before (what on Earth you are doing differently) and after. Also consider whether the wasted programmer time, which is money, is worth the micro-optimization.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
17

This question betrays a lack of understanding of what movement in C++11 is for.

When you copy an object that has pointers or otherwise owns resources, there are two ways to make that copy happen. You can either copy the pointers/resource references, or you can allocate new objects/resources and copy the value of the original ones into the new ones.

In the first case, you are left with two objects that have references to the same object. Qt does this a lot. If you use one object to modify something it references, you are also modifying the other one. You generally need some kind of reference counter in order to not double-delete the pointer or double-release the resource.

In the second case, you are left with two completely separate objects. This is commonly called "value semantics", because if you copy one POD into another, you have two completely separate objects afterwards. Changing one doesn't change another.

Move semantics are a C++11 mechanism to allow objects that normally have value semantics to have reference semantics under certain conditions. It essentially allows an object to steal the pointers/resources referenced by another object instance.

For example, take std::vector; this is just a wrapper around a dynamically allocated and resized array. As with most C++ standard library objects, vector implements value semantics. If you copy a vector, the new vector must allocate a new array and copy each element from the old one into the new one. Once you're done, you have two completely separate arrays.

Move semantics are a way to transfer the array contained within a vector into another. After the operation, the move source object is "empty" (technically in an undefined state, but it is effectively separated from the data it allocated). The new vector now has the exact same pointer that the old vector did; the new vector will delete memory that it didn't allocate.

As you can see, this is all based on the concept of an object owning resources. vector allocates and owns an array; it's destructor will destroy it. That's how you define ownership. Movement is about transferring ownership.

PODs cannot express ownership of pointers or resources, because PODs must have trivial destructors (ie: destructors who don't do anything). Because PODs can't express ownership, there's nothing to move. You can't transfer ownership between objects if they don't own anything.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
8

You have to bring engineering judgement in to play. Imagine for an example that you are talking about whether to use a std::array<int, N> or a std::vector<int> with N items, where N is a compile-time constant.

When N is very small, std::array<int, N> is the clear winner because there is no heap allocation. And copies (and moves which are equivalent to copies) are cheap.

When N is very large, std::vector<int> is the clear winner because although there is a heap allocation, and one can move around the vector with the cost of only moving 3 words, no matter the size of N.

When N == 3, there is no doubt which is the better choice. When N == 3,000,000 there is no doubt which is the better choice.

Your job, as the designer, is to step into that grey area between these two extremes and make the right decision. There is no always-right decision. Performance measurements against your expected use cases go a long way. Use <chrono> for those performance measurements. If you don't know what <chrono> is, search stackoverflow.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
2

Make a class to point to the class with PODs and use std::move on the former.

ggg
  • 1,857
  • 2
  • 21
  • 33