条款三十一:避免默认捕获模式
捕获只能针对与在创建lambda表达式的作用域内可见的非静态局部变量(包括形参),然而实测发现静态局部变量也是可以捕获的。
默认按引用捕获模式的缺陷:
-
lambda表达式的生存周期可能会大于默认捕获的局部变量或形参的生存周期,导致无效引用,而显式列出捕获对象可以起到提醒声明周期的作用,降低出错概率;
默认按值捕获模式的缺陷:
-
捕获裸指针时获得的只是一个裸指针副本,其他地方可能会delete这个指针,比如this指针;
-
按值捕获只能获得捕获当时的值的副本,不能感知到捕获内容在闭包之外的更新;
int num = 1; auto calc = [=](int value) { cout << value + num << “ ”; }; for(int i = 0; i < 5; ++i) { calc(i); ++num; } // 输出 1 2 3 4 5
条款三十二:使用初始化捕获将对象移入闭包
C++14支持通过初始化捕获(广义lambda捕获)将对象移入闭包,见下面代码:
// C++14 void test2() { std::vector<double> data(2, 1.0); auto func = [data = std::move(data)]() { cout << data[0] << endl; }; func(); } // C++11 void test3() { std::vector<double> data(2, 2.0); auto func = std::bind( [](const std::vector<double>& data) { cout << data[0] << endl; }, std::move(data) ); func(); }
条款三十三:对auto&&型别的形参使用decltype,以std::forward之
其实就是用forward+decltype来实现auto&&类型的转发,见下面代码:
auto f = [](auto&& param) { return func(normalize(std::forward<decltype(param)>(param))) }; // 可变长形参 auto f = [](auto&&... param) { return func(normalize(std::forward<decltype(param)>(param)...)) };
条款三十四:优先使用lambda表达式,而非std::bind
lambda表达式比起使用std::bind而言,可读性更好,表达力更强,可能运行效率也更高。