vendredi 28 avril 2017

Confusion about C++ functor/lambda argument-passing in STL algorithms

I like C++11 and its ability to combine STL algorithms to lambdas; it makes the STL much more approachable and useful to everybody. But one thing that I don't understand is what happens inside an STL algorithm (like std::accumulate) regarding object copying or referencing inside the lambda (or wherever functor you give to it).

My three questions are:

  1. Are there any guidelines regarding wherever I should care about pass-by-reference vs. pass-by-value in lambdas/functors?
  2. Does it matter at all if you declare a lambda inside an algorithm that takes its arguments by reference ([](Type &a, Type &b){}), and will it be more optimal than a regular variant; or is it just syntax sugar, the compiler will optimize it anyway, and I could simply omit the ampersands?
  3. Does the C++ Standard has any provision about this?

As for question #2, a quick experiment in Godbolt's GCC page (using compilation flags -stc=c++11 -Os) seems to suggest the latter, as the generated assembly from the code below is identical wherever I use [](T i1, T i2) or [](T &i1, T &i2); I don't know if those results could be generalized to more complex types/objects, however.

#include<array>
#include<numeric>

template <typename T>
T vecSum(std::array<T, 4> &a){
  return std::accumulate(a.begin(), a.end(), T(0),
    [](T i1, T i2) {
        return std::abs(i1) + std::abs(i2);
    }
  );
}

void results() {
    std::array<int, 4> a = {1,-2, 3,-4};
    std::array<int, 4> b = {1,-2,-3, 4};

    volatile int c = vecSum(a) + vecSum(b);
}

Aucun commentaire:

Enregistrer un commentaire