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

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

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

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 的移动构造函数?
  3. 哪个,按值或使用 std::move,应该作为最佳实践首选?

最佳答案

Lambda 捕获本质上是 lambda 对象的成员变量。因此,它们不受任何形式的省略,无论是在初始化中还是在 lambda 的 operator() 重载中的使用。

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

也就是说,根据 C++17 规则返回 lambda 本身不会调用 lambda 本身的复制/移动,因此不需要进一步复制/移动该 lambda 的成员。

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

没有。按值捕获始终复制。

关于c++ - 在返回的 lambda 中复制省略捕获的局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60851447/

相关文章:

c++ - "stat"函数更新慢?

c++ - 当要读取的文件已经打开时,文件读取进入无限循环

C++:使用声明和重载范例

c++ - 什么是复制省略和返回值优化?

c++ - Const 引用以延长对象的生命,然后是 const_cast,这是个好主意吗?

c++ - CUDA:Mark Harris 的并行缩减样本不只是对每个线程 block 求和吗?

c++ - const 内的非 const

c++ - 用于 `std::sort` 的自定义迭代器

c++ - 由于C++17支持数组的shared_ptr,这是否意味着ctor和reset中不再需要T[]的显式删除器?

c++11 - 如何使用右值调用复制构造函数