在返回的 lambda 中复制省略捕获的局部变量
Copy elision for captured local variables in returned lambda
是lambda表达式中的按值捕获([x]
)(或C++14移动捕获[x = std::move(x)]
)中的复制(移动)构造(作为return 值)可能(或保证)被省略?
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() };
}
我的问题是:
- 上述函数中
w
的复制(移动)是否可以(甚至保证)被省略? (我记得显式 std::move
有时会阻止复制省略,而参数的 copy/move 是不可能被省略的。)
- 如果在情况 1 和情况 3 中不会发生复制省略,
w
的按值捕获是否会调用 Widget
的移动构造函数?
- 根据值或使用
std::move
,哪个应该作为最佳实践首选?
Lambda 捕获本质上是 lambda 对象的成员变量。因此,它们不受任何形式的省略,无论是在初始化中还是在 lambda 的 operator()
重载中的使用。
并且因为 constructor/destructor 调用是可观察的行为,编译器不允许在 "as if" 规则下不调用它们(除非编译器可以看到那些 constructors/destructors 的代码并且可以证明它们没有明显的副作用。除此之外,它还必须在整个代码库中遵循该 lambda 的路径。所以基本上,不要指望它)。
也就是说,根据 C++17 规则,lambda 本身的 return 不会调用 lambda 本身的 copy/move,因此不会再调用成员的 copies/moves需要那个 lambda。
will the by-value capture for w call the move constructor of Widget?
没有。按值捕获总是复制。
是lambda表达式中的按值捕获([x]
)(或C++14移动捕获[x = std::move(x)]
)中的复制(移动)构造(作为return 值)可能(或保证)被省略?
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() };
}
我的问题是:
- 上述函数中
w
的复制(移动)是否可以(甚至保证)被省略? (我记得显式std::move
有时会阻止复制省略,而参数的 copy/move 是不可能被省略的。) - 如果在情况 1 和情况 3 中不会发生复制省略,
w
的按值捕获是否会调用Widget
的移动构造函数? - 根据值或使用
std::move
,哪个应该作为最佳实践首选?
Lambda 捕获本质上是 lambda 对象的成员变量。因此,它们不受任何形式的省略,无论是在初始化中还是在 lambda 的 operator()
重载中的使用。
并且因为 constructor/destructor 调用是可观察的行为,编译器不允许在 "as if" 规则下不调用它们(除非编译器可以看到那些 constructors/destructors 的代码并且可以证明它们没有明显的副作用。除此之外,它还必须在整个代码库中遵循该 lambda 的路径。所以基本上,不要指望它)。
也就是说,根据 C++17 规则,lambda 本身的 return 不会调用 lambda 本身的 copy/move,因此不会再调用成员的 copies/moves需要那个 lambda。
will the by-value capture for w call the move constructor of Widget?
没有。按值捕获总是复制。