Vector move constructor is slower than copy constructor

I am working on my first C ++ project, which is a complete CSV parser ( http://en.cppreference.com/w/cpp/container/vector/vector for the ruler it will take constant time. To my surprise, this is significantly accelerated the parser (in accordance with my really rough standard of work time ./main.o on this file ).

I am completely new for optimization, benchmarking and everything else related to customizing C ++ code. Perhaps this optimization is useless even if it works, but despite this, I'm curious why std::move causes a slowdown. Did I miss something?

+5
source share
2 answers

When you copy bufvec, its capacity does not change, but when you move it, its capacity is cleared. So later, when you fill out bufvec, the logarithmic number of distributions is done to expand its capacity again, and such distributions can easily be the bottleneck of your performance.

The move version makes this function faster. But this makes the other code slower. Microprocessor optimization does not guarantee reliable program execution.


Edit by OP:

Solution proposed by Cheers and hth. - Alf Cheers and hth. - Alf in the comments m_bufvec.reserve(row.size()) after moving, fixes the problem and confirms that the above reasoning is correct. Moreover, it is more effective (albeit slightly), because

you avoid copying elements [in bufvec]. If the elements are simple integer values, that doesn't really matter. If the elements are, for example, strings with dynamic allocation, then it really matters.

+8
source

Indeed, it is expected that the first version will be faster. The reason is that:

 auto row(m_bufvec); 

calls a copy of constuctor, which immediately allocates the necessary memory for row . bufvec also saves allocated memory. As a result, reductions for each element are minimized, and this is important because they are related to the number of movements.

In the second version, auto row(std::move(m_bufvec)); bufvec memory becomes the owner of row ; this operation is faster than the copy constructor. But since bufvec lost the allocated memory when you later fill it with an element by element, it will do a lot of redistribution and (expensive) relocation. The number of redistributions is usually logarithmic with a finite vector size.

EDIT

The above explains the "unexpected" results in the main question. Finally, it turns out that the β€œideal” for this operation should move immediately:

 auto row(std::move(m_bufvec); m_bufvec.reserve(row.size()); return row; 

Achieving three goals:

  • no distribution by elements

  • no useless initialization for bufvec

  • there is no useless copying of elements from m_bufvec to row .

+1
source

Source: https://habr.com/ru/post/1263373/


All Articles