类库大魔王的日常

一本流水帐

各种吐槽,倒苦水,开坑,立Flag。毫无营养,慎入!


C++/Go, Windows/Linux/macOS, iOS/Android, server/client development

C++11 lambda表达式tips

C++11加入的lambda表达式是一大进步,大概这样用:

int a = 1;
auto f = [&a](int n)->int {
    return n+a;
};
int b = f(2);

这段代码定义了一个lambda表达式,接受一个int变量参数,返回一个int值,同时又要捕获(即在lambda表达式内访问)外部变量a的引用。

这里有一些tips:

  1. 捕获内建类型变量,即不是class/struct的实例的,如果没有修改的需求,传值比传引用要效率少,一般少1条汇编指令。像上面代码中的&a,不如改成a

  2. 捕获变量列表可以指定多个变量,以逗号分隔,如果有很多变量都要被捕获,方便起见不如直接写一个[&][=],即全部捕获变量引用或全部捕获变量值,实际上编译器生成代码时,只会对lambda表达式中实际使用到的捕获变量生成相应的代码,没用到的都不会有任何冗余代码开销。

  3. 捕获变量如果以值传递,是只读的,在lambda表达式中不能修改,否则编译就会失败。

  4. 要注意捕获变量的生命周期,比如在一个范围内将lambda表达式作为回调体(callback entity)延迟调用,如果该lambda表达式的捕获变量已经被销毁(栈上分配的变量出了范围就自动销毁)再调用lambda表达式,则程序可能就crash了。

  5. lambda表达式虽然可以在函数体内定义,但实际上基本是个编译期行为,编译器会根据需要将lambda表达式作为一个独立的函数生成代码,比如以下代码:

    class C {
        public:
        void lambdaTest() {
            int a = 1;
            auto f = [&a](int n)->int {
                return n+a;
            };
            int b = f(2);
        }
    };
    
    void f() {
        C c;
        c.lambdaTest();
    }
    

    在gcc 7.1的实现中,会分别生成C::lambdaTest()C::lambdaTest()::{lambda(int)#1}::operator()(int) const两个函数的代码,除此之外clang/LLVM,Micrsoft Visual C++和Intel C++基本都是相同的做法。所以一般说来,逻辑上把lambda当成一个普通函数对待即可。但是从编程实践的角度讲,lambda表达式最好不要写太长,越短小越好,不然直接写个独立的函数代码结构会更好。

本文地址:

https://blog.minidump.info/2017/08/cxx11-lambda-tips/

上一篇

把blog托管到Coding Pages

自从重新开始写blog,都是托管在github pages上,然后通过cloudflare中转以及https证书。这一套方案总的说来工作得挺好的,但是,万事就怕但是,在大陆cloudflare的服务并不是特别稳定。后来发现Coding.net也提供Pages服务了,还集成了Let’s Encr...…

blog 全文阅读
下一篇

一次装Windows的经历

妹子新工作居然要求自带电脑,然后就报到前一天晚上开始折腾一台老ASUS笔记本,结果折腾得自己改坏了系统登录密码,再也进不去系统,只能重装解决。说起来已经好多年不装系统了,年纪越大越懒得折腾。从抽屉翻出好久没用过的U盘准备做安装盘,结果用Win32DiskImager烧了几次U盘都不能启动,我以...…

Life 全文阅读