为了账号安全,请及时绑定邮箱和手机立即绑定

在默认情况下,为什么C ++ 11的lambda要求“可变”关键字来进行按值捕获?

在默认情况下,为什么C ++ 11的lambda要求“可变”关键字来进行按值捕获?

C++
墨色风雨 2019-10-05 14:03:54
简短示例:#include <iostream>int main(){    int n;    [&](){n = 10;}();             // OK    [=]() mutable {n = 20;}();    // OK    // [=](){n = 10;}();          // Error: a by-value capture cannot be modified in a non-mutable lambda    std::cout << n << "\n";       // "10"}问题:为什么我们需要mutable关键字?与传递给命名函数的传统参数完全不同。背后的原理是什么?我给人的印象是,按值捕获的全部目的是允许用户更改临时值-否则,使用按引用捕获几乎总是更好,不是吗?有什么启示吗?(顺便说一句,我正在使用MSVC2010。AFAIK,这应该是标准的)
查看完整描述

3 回答

?
MMMHUHU

TA贡献1834条经验 获得超8个赞

您的代码几乎与此等效:


#include <iostream>


class unnamed1

{

    int& n;

public:

    unnamed1(int& N) : n(N) {}


    /* OK. Your this is const but you don't modify the "n" reference,

    but the value pointed by it. You wouldn't be able to modify a reference

    anyway even if your operator() was mutable. When you assign a reference

    it will always point to the same var.

    */

    void operator()() const {n = 10;}

};


class unnamed2

{

    int n;

public:

    unnamed2(int N) : n(N) {}


    /* OK. Your this pointer is not const (since your operator() is "mutable" instead of const).

    So you can modify the "n" member. */

    void operator()() {n = 20;}

};


class unnamed3

{

    int n;

public:

    unnamed3(int N) : n(N) {}


    /* BAD. Your this is const so you can't modify the "n" member. */

    void operator()() const {n = 10;}

};


int main()

{

    int n;

    unnamed1 u1(n); u1();    // OK

    unnamed2 u2(n); u2();    // OK

    //unnamed3 u3(n); u3();  // Error

    std::cout << n << "\n";  // "10"

}

因此,您可以将lambda看作是使用operator()生成的类,除非您说它是可变的,否则该类默认为const。


您也可以将[]内部捕获的所有变量(显式或隐式)视为该类的成员:[=]对象的副本或[&]对象的引用。当您声明lambda时就将它们初始化,就像有一个隐藏的构造函数一样。


查看完整回答
反对 回复 2019-10-05
?
守着星空守着你

TA贡献1799条经验 获得超8个赞

我给人的印象是,按值捕获的全部目的是允许用户更改临时值-否则,使用按引用捕获几乎总是更好,不是吗?


问题是,它“几乎”吗?常见的用例似乎是返回或传递lambda:


void registerCallback(std::function<void()> f) { /* ... */ }


void doSomething() {

  std::string name = receiveName();

  registerCallback([name]{ /* do something with name */ });

}

我认为这mutable不是“几乎”的情况。我认为“按值捕获”类似于“允许我在捕获的实体死亡后使用其值”,而不是“允许我更改其副本”。但这也许可以争论。


查看完整回答
反对 回复 2019-10-05
  • 3 回答
  • 0 关注
  • 509 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信