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).
It's faster because moving allows the source to be left in a invalid state, so you can steal it's resources. For example, if a object holds a pointer to a large block of allocated memory, a move can simply steal the pointer while a copy must allocate its own memory and copy the whole memory block.
Std::move is not faster than straight up copying.
Q: When should it be used? A: You should use std::move if you want to call functions that support move semantics with an argument which is not an rvalue (temporary expression).
The move constructor is much faster than a copy constructor because it doesn't allocate memory nor does it copy memory buffers.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With