lambda表达式捕获模式的陷阱分析和演示

#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;

vector<std::function<bool(int)>> gv;

void myfunc() {
    srand((unsigned)time(nullptr));
    int tempvalue = rand() % 6;
    gv.push_back(
        //[&](int tv) {
        [=](int tv) {
            if(tv % tempvalue == 0) {    // 如果tv是tmpvalue的倍数
                return true;
            }
            return false;
        }
    );
}

void myfunc_static() {
    static int tempvalue = 4; // 静态变量不需要捕获,也捕获不到
    gv.push_back(
        //[&](int tv) {
        [](int tv) {
            cout << "static tempvalue:" << tempvalue << endl;
            if(tv % tempvalue == 0) {    // 如果tv是tmpvalue的倍数
                return true;
            }
            return false;
        }
    );
    ++tempvalue;
}

class AT {
public:
    int m_tempvalue = 10;
    void addItem() {
        gv.push_back(
            //[&](int tv) {
            //=是按值捕获的意思
            //我们会认为这个[=]是按值捕获,使我们能够访问成员变量m_tempvalue
            //所以我们顺理成章的认为,这里这个lambda表达式所用的m_tempvalue是按值捕获
            //[=](auto tv) { //=等价于有this
            //[=](int tv) { //=等价于有this.用了=用了&就默认等于添加了this
            [this](int tv) {
            //[&](int tv) {
                cout << "m_tempvalue: " << m_tempvalue << endl; // this->m_tempvalue
                if(tv % m_tempvalue == 0) {    // this->m_tempvalue
                    return true;
                }
                return false;
            }
        );
        int tmpvalueCopy = m_tempvalue;
        gv.push_back(
            [=](int tv) {
                cout << "tmpvalueCopy: " << tmpvalueCopy << endl; // this->m_tempvalue
                if(tv % tmpvalueCopy == 0) {
                    return true;
                }
                return false;
            }
        );
        gv.push_back(
            [abc = m_tempvalue](int tv) {
                cout << "abc: " << abc << endl;
                if(tv % abc == 0) {
                    return true;
                }
                return false;
            }
        );

    }
};

int main() {
    //一:捕获列表中的&:捕获外部作用域中所有变量,并作为引用在lambda表达式中使用;
    //按照引用这种捕获方式,或导致lambda表达式包含绑定到局部变量的引用
    myfunc();
    cout << gv[0](10) << endl; // 非法调用,会产生不可预料的问题
    //二:形参列表可以使用auto
    //c++14允许在lambda表达式的形参列表中使用auto
    //引用捕获方式超出反问的情形也叫做“引用悬空",采用按值捕获的方式可以解决这个问题
    //三:成员变量的捕获问题
    AT* pat = new AT();
    //pat->m_tempvalue = 90;
    pat->addItem();
    pat->m_tempvalue = 90; // 放在这里并不会修改tmpvalueCopy的数值,没有修改副本,也就是gv[3]
                           // 这里会修改gv[2]中的m_tempvalue数值,因为它和this绑定
    delete pat; // 这里删除gv[2]就没有办法使用了,因为他和this->m_tempvalue绑定
    // 结论:lambda表达式的执行结果正确与否,取决于pat对象是否存在,
    // 只有pat对象存在,这个lambda表达式执行才正确
    // 我们大家首先要明确一点:捕获这个概念,只针对在创建lambda表达式的作用域内可见的
    // 非静态局部变量(包括形参)
    // m_teempvalue并不是非静态局部变量,m_tempvalue是AT类的成员变量,成员变量是不能被捕获到的
    // this:指向本身,所以这里你用[=]捕获的是this指针值
    //cout << gv[1](10) << endl;
    cout << gv[2](10) << endl;
    // 四:广义lambda捕获:c++14:generalized lambda capture:
    cout << gv[3](10) << endl;
    // 五:静态局部变量:捕获这种事,是不包含静态局部变量的,也就是说静态局部变量是不能被捕获的
    // 但是可以在lambda使用,另外静态局部变量是保存在静态存储区,它的有效期一直到程序结束
    // 但是这种对static变量的使用有点类型按照引用捕获的效果
    myfunc_static();
    cout << gv[4](10) << endl;
    myfunc_static();
    cout << gv[5](10) << endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值