条款31.避免默认捕获模式
默认捕捉模式的问题:
- 使用引用模式捕捉,如果捕捉对象生命周期过短,将有空悬危险
- 使用默认值捕捉模式,会将this误捕捉,从而将其成员误以为捕捉成功
- 静态区变量也同样无法捕获,但是会被误以为捕获了
//一旦捕捉的变量的生命周期短于lambda表达式就有空悬的危险
void Test(){
auto Obj = xxx;
filers.emplace_back([&](){
Obj.DoSomething();//危险操作,引用可能空悬
});
}
更好的方式是采用广义lambda捕捉,也叫做初始化捕捉。
void Widget::addFilter() const{
filter.emplace_back(
[divisor = divisor](int value){
{ return value % divisor == 0; }
}
);
}
条款32.使用初始化捕获将对象移入闭包
在C++14中你可以使用初始化捕获的方式:
auto func = [pw = std::move(pw)](){
return pw->isValidated() && pw->isArchived();
}
在C++11中你需要使用bind的配合来实现这一点
auto func = std::bind(
[](const std::vector<double>& data){
//do something...
},
std::move(data)
);
有了这个方法,你可以放心的将初始化值绑定到lambda表达式了。
条款33.对auto&&类型的形参使用decltype来std::forward
看代码:
// 这个lambda表达式的效率是有问题的,即使是右值传递到这个lambda,还是会需要复制
auto f = [](auto x){ return func(normalize(x)); };
//所以我们会用到auto&&的万能引用以进行完美转发,这个时候获取类型的时候就要用到decltype
auto f = [](auto&& x) { return func(normalize(std::forward<decltype(x)>(x))) };
条款34.优先使用lambda,而不是std::bind
- lambda表达式相比bind而言可读性更好,效率更高也更灵活
- 在C++11的场合,还可以用于初始化捕捉,以及多态函数对象的情况,其他都可以使用lambda表达式替代。
多态函数对象
往往在函数式编程中会用到,C++11由于还不支持lambda的auto,所以需要有以下实现。
class PolyWidget{
public:
template<typename T>
void operator()(const T& param);
}
PolyWidget pw;
auto boundPW = std::bind(pw, _1);
//这样就可以任意组合了
boundPW(1930);//可以传递int
boundPW(nullptr);//可以传递空指针
boundPW("Rosebud");//传递字符串字面量
在C++14则可以直接使用auto作为lambda形参即可实现上述功能。