物联网
您现在所在的位置:首页>企业动态>物联网

C++的lambda是函数还是对象?

编辑:学到牛牛IT培训    发布日期: 2022-02-14 09:58:13  

关于C++++的lambda是函数还是对象,这其实不是一个一概而论的问题。

先说结论:

对于有捕获的lambda,其等价于对象。

对于没有任何捕获的lambda,其等价于函数!

首先,很多C++程序员从lambda 用法上反推容易发现是对象,因为lambda可以捕获!这是函数做不到的。的确,比如:

int n = 100;
auto foo = [n](int a) {
    return a > n;
};
cout<< foo(99);

如果编译器要实现foo,大致类比这种写法(可能真实的实现细节不是这样,但思路类似)∶

struct Foo {
    Foo(int i) {n=i;}
    bool operator()(int a) {
        return a > n;
    }
private:
    int n;
};
...
int n = 100;
Foo foo(n);
cout<< foo(99);

如果是引用捕获了变量,那么struct内有一个指针成员持有被引用捕获的变量的地址。

比如:

set<int> ns = {100, 200, 300};
auto foo = [&ns](int a) {
    return ns.find(a);
};
cout<< foo(99);
大致等价于:
struct Foo {
    Foo(set<int>* p) {p_ns = p;}
    bool operator()(int a) {
        auto &ns = *p-ns;
        return ns.find(a);
    }
private:
    set<int>* p_ns;
};
...
set<int> ns = {100, 200, 300};
Foo foo(&ns);
cout<< foo(99);

然而……这并不是全部!

在没有捕获任何东西的时候,lambda其实是等价于普通的函数的!可以用Linux C中函数pthread_create()来验证!它只能接收一个参数是void*,返回值也是void*的回调函数。

神奇的是,无参的lambda也可以被pthread_create()使用!

#include <iostream>
#include <pthread.h>
using namespace std;
struct A {
    void* operator()(void*) {
        cout<<"xxxx"<<endl;
        return nullptr;
    }
};
int main() {
    A a;
    a(NULL);
    pthread_t t;
    //pthread_create(&t, NULL, a, NULL); // 编译失败
    auto cb = [](void*)->void* {
        cout<<"xxxx"<<endl;
        return nullptr;
    };
    pthread_create(&t, NULL, cb, NULL); // 编译通过
    pthread_join(t, NULL);
    return 0;
}

上面代码还可以再改一下,让cb去捕获一个变量, 比如:

    auto cb = [&](void*)->void* {
        cout<<"xxxx"<<endl;
        return nullptr;
    };
    pthread_create(&t, NULL, cb, NULL);

这时,给pthread_create()传入cb同样会编译失败!错误信息:

cb.cpp: In function ‘int main()’:
cb.cpp:23:30: error: cannot convert ‘main()::<lambda(void*)>’ to ‘void* (*)(void*)’
   23 |     pthread_create(&t, NULL, cb, NULL);
      |                              ^~
      |                              |
      |                              main()::<lambda(void*)>
In file included from /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:35,
                 from /usr/include/x86_64-linux-gnu/c++/9/bits/gthr.h:148,
                 from /usr/include/c++/9/ext/atomicity.h:35,
                 from /usr/include/c++/9/bits/ios_base.h:39,
                 from /usr/include/c++/9/ios:42,
                 from /usr/include/c++/9/ostream:38,
                 from /usr/include/c++/9/iostream:39,
                 from cb.cpp:1:
/usr/include/pthread.h:200:15: note:   initializing argument 3 of ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)’
  200 |       void *(*__start_routine) (void *),
      |       ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~

这其实也不难理解,C++在lambda的设计上也贯彻着零开销 (Zero Overhead)原则,也就是C++不在性能上干多余的事,显然函数比对象开销更小。所以即使同为lambda,在有无捕获的时候,其底层实现其实是截然不同的!


声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。

免费试学
课程好不好,不如实地听一听

封闭学习

2

1

联系我们

电话:028-61775817

邮箱:1572396657@qq.com

地址:成都高新西区西芯大道4号

  • 学到牛牛在线咨询

    扫一扫,免费咨询

  • 学到牛牛公众号

    微信公众号

学一流技术,找高薪工作

7-24小时服务热线:

028-61775817

版权声明 网站地图

蜀ICP备2021001672号

课程问题轻松问