[C++] - lambda capture的成员函数 异步调用

关于lambda capture:

If the capture-default is &, subsequent simple captures must not begin with &.

struct S2 { void f(int i); };
void S2::f(int i)
{
    [&]{};          // OK: by-reference capture default
    [&, i]{};       // OK: by-reference capture, except i is captured by copy
    [&, &i] {};     // Error: by-reference capture when by-reference is the default
    [&, this] {};   // OK, equivalent to [&]
    [&, this, i]{}; // OK, equivalent to [&, i]
}

If the capture-default is =, subsequent simple captures must begin with & or be *this (since C++17) or this (since C++20).

struct S2 { void f(int i); };
void S2::f(int i)
{
    [=]{};          // OK: by-copy capture default
    [=, &i]{};      // OK: by-copy capture, except i is captured by reference
    [=, *this]{};   // until C++17: Error: invalid syntax
                    // since c++17: OK: captures the enclosing S2 by copy
    [=, this] {};   // until C++20: Error: this when = is the default
                    // since C++20: OK, same as [=]
}

Any capture may appear only once:

struct S2 { void f(int i); };
void S2::f(int i)
{
    [i, i] {};        // Error: i repeated
    [this, *this] {}; // Error: "this" repeated (C++17)
}

如果lambda capture的是成员函数,这个lambda在它所capture的类对象释放后异步调用:

class A:
{
public:
    int func()
    {
        std::ofstream myfile("example.txt");
        if (myfile.is_open())
        {
            myfile << "Write from child thread.\n";
            myfile.close();
        }
        else
        {
            std::cout << "Unable to open file";
        }
    }

    void detach()
    {
        std::thread t([this]() {
            std::this_thread::sleep_for(std::chrono::milliseconds(3000));
            func();
        });
        t.detach();
    }
};

int main()
{
    {
        A a;
        a.detach();
    }

    std::cout << "main end" << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    return 0;
}

当main函数执行到打印“main end”时,a对象已经释放,但是它创建的子线程中调用了它的成员函数依然可以正常执行。这是因为成员函数在转变为汇编代码时与普通的函数一样,只不过会将this指针作为它的第一个参数传入,而且a对象的func()方法中没有调用A的其他成员变量,因此不会发生crash。正确的写法应该是在进入lambda的时候判断此时它capture的this指针所指向的对象是否还是有效的:

#define RETURN_FROM_LAMBDA_IF_DEAD(x) \
    auto sharedThis = x.lock(); \
    if(!sharedThis) \
        return;

class A: public std::enable_shared_from_this<A>
{
public:
    int func()
    {
        std::ofstream myfile("example.txt");
        if (myfile.is_open())
        {
            myfile << "Write from child thread.\n";
            myfile.close();
        }
        else
        {
            std::cout << "Unable to open file";
        }
    }

    void detach()
    {
        std::thread t([weakThis = weak_from_this(), this]() {
            RETURN_FROM_LAMBDA_IF_DEAD(weakThis);
            std::this_thread::sleep_for(std::chrono::milliseconds(3000));
            func();
        });
        t.detach();
    }
};

int main()
{
    {
        A a;
        a.detach();
    }

    std::cout << "main end" << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    return 0;
}

另外,如果确实想要在lambda中调用this指向对象的成员函数且这个成员函数没有调用成员变量,可以把这个成员函数定义成private static,这样就不会有上面说的问题。

 

参考链接:

https://en.cppreference.com/w/cpp/language/lambda

https://stackoverflow.com/questions/57654701/member-function-captured-by-lambda-asynchronously-dispatch-issue

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值