3

Is the copy (move) construction in a by-value capture ([x]) (or C++14 move capture [x = std::move(x)]) in a lambda expression (as a return value) possible (or guaranteed) to be elided?

auto param_by_value(Widget w) {
    // manipulating w ...
    return [w] { w.doSomeThing(); };
}
auto param_by_move(Widget w) {
    // manipulating w ...
    return [w = std::move(w)] { w.doSomeThing() };
}
auto local_by_value() {
    Widget w;
    // manipulating w ...
    return [w] { w.doSomeThing(); };
}
auto local_by_move() {
    Widget w;
    // manipulating w ...
    return [w = std::move(w)] { w.doSomeThing() };
}

My questions are:

  1. Is the copy (move) for w in the above functions possible (or even guaranteed) to be elided? (I recall the explicit std::move would sometimes prevent copy elision, and the copy/move for parameters are impossible to be elided.)
  2. If copy elision is not going to happen in case 1 and 3, will the by-value capture for w call the move constructor of Widget?
  3. Which, by value or using std::move, should be preferred as the best practice?
Ruifeng Xie
  • 813
  • 4
  • 16

1 Answers1

5

Lambda captures are essentially member variables of a lambda object. As such, they are not subject to any form of elision, either in their initialization or their use in the lambda's operator() overload.

And because the constructor/destructor calls are observable behavior, the compiler is not allowed to not call them under the "as if" rule (unless the compiler can see the code for those constructors/destructors and can prove that there are no visible side-effects of them. It would also have to follow the path of that lambda throughout your codebase, among other things. So basically, don't count on it).

That being said, the return of the lambda itself under C++17 rules will not invoke a copy/move of the lambda itself and therefore no further copies/moves of the members of that lambda would be required.

will the by-value capture for w call the move constructor of Widget?

No. By-value captures always copy.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982