【问题标题】:capture member variable by value按值捕获成员变量
【发布时间】:2010-09-15 13:22:02
【问题描述】:

使用 C++11 lambda 表达式时如何按值捕获成员变量?

使用[my_member] 语法似乎不起作用,隐式捕获使用this 指针。需要的是一种明确指定成员变量的捕获类型的方法。这可能吗?

我现在的解决方法是:

void member_function()
{
    std::shared_ptr<my_member_class> my_member_copy = my_member; // this shouldn't be necessary
    std::async([=]{ std::cout << *my_member_copy; });
    // std::async([=]{ std::cout << *my_member_; }); // wrong, my member could be potentially out of scope
}

【问题讨论】:

    标签: c++ lambda c++11


    【解决方案1】:

    我认为您不能按值捕获成员,您可以捕获 this,但由于该成员是 this 的一部分,您将使用共享成员而不是新变量。

    不知道你的会员是什么类型,这样的东西应该可以工作:

    auto copy = my_member;
    std::async([copy]{ std::cout << copy; });
    

    我不明白您为什么在示例中使用shared_ptr,如果您想按价值捕获肯定shared_ptr 是您应该考虑的最后一件事。

    【讨论】:

    • 我需要按值捕获才能增加 shared_ptr 引用计数。否则,当父对象被销毁时,该对象将被销毁,从而导致异步操作中的潜在访问冲突。 (忘记在 lambda 中添加 *)。我看不出您的示例与我的示例有何不同。
    • “不知道你的成员是什么类型,这样的东西应该起作用:”,我写 std::shared_ptr 而不是 auto 的原因是要明确“my_member”的类型,即 shared_ptr .
    【解决方案2】:

    不幸的是,我认为没有直接的方法可以做到这一点,但我可以想出几种方法来捕获成员而无需制作额外的副本。

    第一个选项与您的示例类似,但使用局部变量的引用:

    void member_function()
    {
       std::shared_ptr<my_member_class> &my_member_ref = my_member;
       // Copied by the lambda capture
       std::async([my_member_ref]{ std::cout << *my_member_ref; });
    }
    

    请注意,在 4.6.2 之前的 GCC 版本中存在导致值无法复制的错误。见Capturing reference variable by copy in C++0x lambda

    第二种方法是使用 bind 来制作副本:

    void member_function()
    {
       // Copied by std::bind
       std::async(std::bind([](const shared_ptr<my_member_class>& my_member){
          std::cout << *my_member; }, my_member));
    }
    

    在此示例中,bind 将创建自己的 my_member 副本,然后此副本将通过引用传递给 lambda 表达式。

    【讨论】:

    • 你的例子都与我的例子不同。
    • @ronag 我的示例和您的解决方法之间的主要区别在于我的示例不会额外复制my_member。我的第一个示例仅将成员绑定到本地引用,允许在 lambda 捕获中按值捕获它,而无需先复制。我的第二个示例是一种避免同时使用局部变量的方法,使用 bind 按值而不是 lambda 捕获来捕获 my_member
    • @ronag:rkjnsn 是对的,他的示例在构造my_member_copy 时保存了增量/减量/指针复制,因此应该更快。你为什么要否决他的回答?
    • @marton78:我无法想象任何现代编译器都不会删除不必要的副本。
    • 是的,我知道复制省略,但在这种情况下不满足其标准,因为两个副本的来源都不是临时的:1)my_member 在构造 my_member_copy 时不是临时的2) my_member_copy 在构造 lambda 时不是临时的。
    【解决方案3】:

    由于您的问题是关于 C++11 这不是一个真正的答案,但在 C++14 中您可以这样做:

    void member_function()
    {
        std::async([my_member=my_member]{ std::cout << *my_member; });
    }
    

    它的作用与您自己的“变通办法”相同(如果 my_member 是 shared_ptr)。

    【讨论】:

      【解决方案4】:
      auto& copy = my_member;
      std::async([copy]{ std::cout << copy; });
      

      auto&(上图)也可以工作并且避免复制两次。虽然这种方法比传递 [this] 更符合语法,但它避免了将对 [this] 指向的对象的依赖传递到闭包中。

      【讨论】:

      • 这确实有效,我仔细检查了它确实是通过复制而不是通过引用来捕获的。谢谢!
      【解决方案5】:

      现在,我遇到了同样的问题并自己解决了:

      1. 捕获this 指针。
      2. 然后在 lambda 中编写 this-&gt;member 语法:

      也就是说,

       std::async([this]{ std::cout << this->my_member_; } ); 
       //          ^^^^                ^^^^^^ use this syntax
       //           | 
       //           ^
       //           capture `this` as well
      

      它对我有用。我希望它也对你有用。但是,我对这些知识并不完全满意。在我工作之后,我会寻找为什么需要这种语法的原因,或者它是一个编译器错误。我正在使用GCC 4.5.0 (MinGW)。

      好吧,我发现以下主题说应该捕获 this 指针才能使用该类的成员。

      【讨论】:

      • 但是这捕获了“this”而不是实际的成员变量,所以如果“this”被删除,那么它会导致未定义的行为。
      猜你喜欢
      • 2012-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-15
      相关资源
      最近更新 更多