0

We have a pretty huge code base, sometimes with performance issues. Move semantics is not used at all. I am wondering how could I find places where move semantics might be useful. Do you have any experience how to localize such a places?

pappati
  • 171
  • 1
  • 9

2 Answers2

4

Since the standard containers have been updated to move elements whenever possible, a good place to start would be types that are stored (by value) in standard containers. If you make them MoveConstructible and MoveAssignable (and be sure to make the move operations noexcept where possible so e.g. std::vector will actually move not copy) then all code using containers of those elements can potentially benefit.

Other candidates are any non-trivial types that are passed to functions or returned from functions by value.

Of course another approach is the usual one for any performance issues: profile the code and find out what's slow. If it's due to lots of copying then consider if the copies can be avoided, and if not whether implementing move semantics might help. If the slowness isn't due to lots of copying then move semantics probably won't help.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
1

Move construction is a great feature because once you add a move constructor you get all the performance benefit "for free". Sure, you can explicitly move objects, but many uses of the move constructor are actually implicit.

Some places (far from an exhaustive list) that benefit once you add a move constructor to a class would be:

std::vector<T> vec;
vec.push_back(T());                //implicit move into array
std::sort(vec.begin(), vec.end()); //may move if std::swap performs swap
T obj = foo();                     //move construct if compiler doesn't apply RVO
T obj2 = obj + T();                //technically same as the line above

The great part about it is that once you add a move constructor to the class (usually only a few lines of code) you don't have to change ANY other code to start reaping the benefits of move!

Your biggest gains would most likely be in loops adding elements to containers, but you get an improvement in all of these areas just by adding a move constructor (which is often trivial to write).

However, 99% of the classes that will benefit from move are classes which allocate memory or resources, because move allows you to replace a deep copy with a shallow copy. Most other classes (such as classes that are just record types) don't gain anything from move.

Robert Mason
  • 3,949
  • 3
  • 31
  • 44
  • 2
    The `sort` example uses **non-member** `swap()`, which _might_ be overloaded to call a member `swap()`. It would be more accurate to say it can move if swapping is done by `std::swap`. The RVO examples are not very useful, since any half-decent compiler will elide copies/moves anyway with optimisation enabled, so adding move semantics to existing `CopyConstructible` classes won't do anything for those cases in practice. – Jonathan Wakely Jul 17 '13 at 17:30
  • Absolutely correct. However, too many people still use non-"half decent" compilers... :P – Robert Mason Jul 17 '13 at 18:41
  • Which compilers support rvalue references but don't do copy elision in those cases? – Jonathan Wakely Jul 18 '13 at 07:34
  • That was tongue in cheek, sorry. I didn't mean that an actual compiler existed that supported rvalue reference but not RVO. Rather was lamenting the number of people who still use TC and ancient versions of (now decent) compilers. – Robert Mason Jul 18 '13 at 14:46
  • `std::sort` is still a good example as it does not have to use only `swap` but may also use move construction and move assignment. The libc++ implementation uses a combination of all three of these operations. – Howard Hinnant Jul 18 '13 at 15:38