C ++ 11 lambdas:成员变量capture gotcha [英] C++11 lambdas: member variable capture gotcha

查看:144
本文介绍了C ++ 11 lambdas:成员变量capture gotcha的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下代码:

#include <memory>
#include <iostream>

class A
{
public:
    A(int data) : data_(data)
    { std::cout << "A(" << data_ << ")" << std::endl; }
    ~A() { std::cout << "~A()" << std::endl; }
    void a() { std::cout << data_ << std::endl; }
private:
    int data_;
};

class B
{
public:
    B(): a_(new A(13)) { std::cout << "B()" << std::endl; }
    ~B() { std::cout << "~B()" << std::endl; }
    std::function<void()> getf()
    {
        return [=]() { a_->a(); };
    }
private:
    std::shared_ptr<A> a_;
};

int main()
{
    std::function<void()> f;
    {
        B b;
        f = b.getf();
    }
    f();
    return 0;
}

这里看起来像是捕获 a_ 按值的共享指针,但是当我在Linux(GCC 4.6.1)上运行它时,会打印:

Here it looks like I'm capturing a_ shared pointer by value, but when I run it on Linux (GCC 4.6.1), this is printed:

A(13)
B()
~B()
~A()
0

显然,0是错误的,因为A已经被破坏了。它看起来像实际被捕获,并用于查找 this-> a _ 。当我将捕获列表从 [=] 更改为 [=,a _] 时,我的怀疑被确认。然后输出正确的输出并且对象的生命周期如预期的那样:

Obviously, 0 is wrong, because A is already destroyed. It looks like this is actually captured and is used to look up this->a_. My suspicion is confirmed when I change the capture list from [=] to [=,a_]. Then the correct output is printed and the lifetime of the objects is as expected:

A(13)
B()
~B()
13
~A()

问题:

这种行为是由标准,实现定义还是未定义指定的?

Is this behaviour specified by the standard, implementation-defined, or undefined? Or I'm crazy and it's something entirely different?

推荐答案


这是标准指定的行为

Is this behaviour specified by the standard

是的。捕获成员变量总是通过捕获 this ;它是访问成员变量的唯一方法。在成员函数范围内,_ 等效于(* this).a _

Yes. Capturing member variables is always done via capturing this; it is the only way to access a member variable. In the scope of a member function a_ is equivalent to (*this).a_. This is true in Lambdas as well.

因此,如果你使用 this (隐式或显式)必须确保对象在lambda实例周围仍然有效。

Therefore, if you use this (implicitly or explicitly), then you must ensure that the object remains alive while the lambda instance is around.

如果要按值捕获它,您必须明确这样做:

If you want to capture it by value, you must explicitly do so:

std::function<void()> getf()
{
    auto varA = a_;
    return [=]() { varA->a(); };
}

如果您需要规格报价:


lambda表达式的复合语句产生函数调用操作符的函数体(8.4),但是为了查找名称(3.4),确定类型和值这个(9.3.2)和使用(* this)(9.3.1),
将引用非静态类成员的id表达式转换为类成员访问表达式复合语句在lambda的上下文中被考虑 - 表达式。

The lambda-expression’s compound-statement yields the function-body ( 8.4 ) of the function call operator, but for purposes of name lookup (3.4), determining the type and value of this (9.3.2) and transforming id-expressions referring to non-static class members into class member access expressions using (*this) ( 9.3.1 ), the compound-statement is considered in the context of the lambda-expression.

这篇关于C ++ 11 lambdas:成员变量capture gotcha的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆