C++读书笔记

超精简Effective Modern C++ 第六章 Lambda表达式

条款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形参即可实现上述功能。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注