Capture cost by reference / value in lambda function?

Consider the following code:

#include <iostream> #include <algorithm> #include <numeric> int main() { const unsigned int size = 1000; std::vector<int> v(size); unsigned int cst = size/2; std::iota(v.begin(), v.end(), 0); std::random_shuffle(v.begin(), v.end()); std::cout<<std::find_if(v.begin(), v.end(), [&cst](const int& i){return i == cst;})-v.begin()<<std::endl; std::cout<<std::find_if(v.begin(), v.end(), [=](const int& i){return i == cst;})-v.begin()<<std::endl; return 0; } 

This code fills the vector with values, shuffles it, and then searches for the index of the specified value (this is just an example illustrating my problem). This cst value can be written by reference or by value in a lambda function.

My question is: is there a performance difference between the two versions or will they be optimized in the same way by the compiler?

Is it a good rule to pass constant fundamental types by values ​​and constant classes by reference (as in ordinary functions)?

+4
source share
3 answers

In practice, there is no difference in performance for small types.

With clang -O3 I get identical code in both cases. Without optimization, clang generates different code, and the copying version is less than one instruction.

 $ clang ref.cpp -O3 -std=c++11 -S -o ref.s $ clang cpy.cpp -O3 -std=c++11 -S -o cpy.s $ diff ref.s cpy.s 

There is a slight difference related to the constant.

Copy capture gives you a const unsigned value. This will not compile:

 unsigned cst = 123; [=](const int& i){ return i == ++cst; } 

A link-capture of a non-constant variable results in a non-constant unsigned& . This changes the original value as a side effect:

 unsigned cst = 123; [&](const int& i){ return i == ++cst; } 

Generally, copying large objects should be avoided. If small objects should be constant in the lambda area, but not constant in the current area, copy-capture is a good choice. If the lambda has a longer lifespan than the local object, then copy-copy is the only option.

+6
source

Capturing lambda doesn't really matter. The difference between them:

 int x = y; for (...) if (x == z) ... 

and

 const int& x = y; for (...) if (x == z) ... 

That is, keeping a link to const int vs to get a copy. int The first version will never be slower, but I think that the optimizer will be able to create the same code for both. Compile both versions and parse to see what happens.

+2
source

cst is an unsigned int , so this is unlikely to make a difference. However, if you do this with a large class that has a significant amount of data in it, it may matter, passing by reference will be faster.

Another thing to consider in this case is that the object is copied only once when the vector is repeated. If you look at the STL functions, most things are passed by a const reference or a regular link, I don’t understand why the capture of variables should be any. Although, unfortunately, you cannot capture a variable as const.

Of course, you always need to be careful when passing by reference, because you can change it, I think that in this case it is best to just go as a link to const.

The last thing to consider is that since the compiler can optimize the difference, you should probably just use a form that you think indicates your intention best. Therefore, I agree that you should

pass constant fundamental types by value and constant classes by reference

+1
source

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


All Articles