在返回的lambda中复制捕获的局部变量的省略号

时间:2020-03-25 14:59:12

标签: c++ c++17 copy-elision

在lambda表达式(作为返回值)中按值捕获([x])(或C ++ 14移动捕获[x = std::move(x)])中的复制(移动)构造是否可能(或保证)被淘汰?

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() };
}

我的问题是:

  1. 是否可以消除(甚至保证)上述功能中w的副本(移动)? (我记得显式std::move有时会阻止复制省略,并且参数的复制/移动是无法消除的。)
  2. 如果情况1和3不会发生复制省略,则w的按值捕获会调用Widget的move构造函数吗?
  3. 按值或使用std::move,哪个应该是最佳做法?

1 个答案:

答案 0 :(得分:4)

Lambda捕获本质上是lambda对象的成员变量。因此,它们在初始化或在lambda的operator()重载中使用时都不受任何形式的修饰。

并且由于构造函数/析构函数的调用是可观察到的行为,因此不允许编译器在“好像”规则下调用它们(除非编译器可以看到这些构造函数/析构函数的代码,并且可以证明没有构造函数/析构函数可见的副作用。此外,它还必须遵循整个代码库中lambda的路径。因此,基本上,不要指望它。)

话虽如此,根据C ++ 17规则返回的lambda本身不会调用该lambda本身的副本/移动,因此不需要该Lambda成员的其他副本/移动。

w的按值捕获会调用Widget的move构造函数吗?

不。按值捕获总是复制。

相关问题