Reputation: 7526
I have read several articles and answers in SO (in particular this), but they do not provide the full answer to my question. They tend to focus on special cases where the move semantic is as fast as copying a pointer, but that is not always the case.
For example consider this class:
struct Big {
map<string, unsigned> m;
vector<unsigned> v;
set<string> s;
};
And this function:
Big foo();
If foo
returns by value and the copy cannot be optimized via RVO
, the compiler will apply the move semantic, which implies 3 moves, one for each class member. If the class members were more than 3, then I would have even more operations. If foo returned the Big
object by pointer (smart pointer maybe) it would always be 1 operation.
To make things even more interesting, Big
objects have a non local life span: they are kept in some data structures for the duration of the application. So you might expect the Big
objects to be moved around multiple times during their life and the cost of 3 operations (move semantic) vs 1 operation (pointer) keeps burdening the performance long after the objects were returned by foo
.
Given that background information, here are my questions:
1 - First of all I would like to be sure about my understanding of the move semantic performance: is it true that in the example above moving Big object is slower than copying pointers?
2 - Assuming the move semantic is indeed slower, would I accept to return Big objects by pointer or are there better way to achieve both speed and nice API (I consider returning by value a better API)?
[EDIT]
Bottom line: I like to return by value, because if I introduce one single pointer in the API then they spread everywhere. So I would like to avoid them. However I want to be sure about the performance impact. C++ is all about speed and I cannot accept blindly the move semantic without understanding the performance hit.
Upvotes: 0
Views: 397
Reputation: 238371
they are kept in some data structures for the duration of the application. So you might expect the Big objects to be moved around multiple times during their life
I don't agree with this conclusion. Elements of most data structures tend to be quite stable in memory. Exception are unreserved std::vector
and std::string
, and other structures based on vector such as flat maps.
If foo returns by value and the copy cannot be optimized via RVO
So, implement foo
in a way that can be optimised via RVO. Preferably in such way that a non-move is guaranteed in C++17. This is fast, and a convenient API, so is what you should prefer.
1 - First of all I would like to be sure about my understanding of the move semantic performance: is it true that in the example above moving Big object is slower than copying pointers?
It is true. Moving Big
is relatively slower than copying a pointer. They are both rather light operations in absolute terms through (depending on context).
When you think about returning a pointer to a newly created object, you must also think about the lifetime of the object and where it is stored. If you're thinking of allocating it dynamically, and returning a pointer to the dynamic object, then you must consider that the dynamic allocation may be much more expensive than the few moves of the member objects. And furthermore, all of this may be insignificant in relation to all of the allocations that the std::map
and other containers will do, so none of this deliberation may end up mattering in the end.
In conclusion: If you want to know what is faster, then measure. If one implementation measures significantly faster, then that implementation is probably the one that is faster (depending on how good you are at measuring).
Upvotes: 3