【问题标题】:Copy elision for captured local variables in returned lambda在返回的 lambda 中为捕获的局部变量复制省略
【发布时间】:2020-03-25 14:59:12
【问题描述】:

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

【问题讨论】:

  • 但是返回的 lambda 不会像保证的那样进行复制/移动。 :)

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


【解决方案1】:

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

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

话虽如此,在 C++17 规则下返回 lambda 本身不会调用 lambda 本身的复制/移动,因此不需要进一步复制/移动该 lambda 的成员。

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

没有。按值捕获总是复制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    • 2020-12-05
    • 2021-12-19
    • 1970-01-01
    • 2020-02-13
    • 2023-03-08
    • 1970-01-01
    相关资源
    最近更新 更多