C++中的闭包

      在编程语言中,闭包(closure),又称为词法闭包(lexical closure)或函数闭包(function closure),是一种在具有一流函数的语言中(a language with first-class functions)实现词法作用域名称绑定的技术。从操作上来说,闭包是一个将函数与环境一起存储的记录。环境是一个映射,将函数的每个自由变量(free variable)(在本地使用但在封闭范围内定义的变量)与创建闭包时名称绑定的值或引用相关联。与普通函数不同,闭包允许函数通过闭包的值或引用的副本来访问这些捕获的变量,即使在函数作用域之外调用该函数也是如此。

      闭包是编程中的一个通用概念,起源于函数式编程。谈论C++中的闭包时,总是带有lambda表达式
      1.在C++中,lambda表达式是用于创建特殊临时对象的语法,其行为类似于函数对象的行为。
      2.C++标准特意将这种类型的对象称为闭包对象(closure object)。这与闭包的更广泛定义有点不一致,闭包指的是从定义变量的环境中捕获变量的任何函数,无论是否匿名。
      3.就标准而言,所有lambda表达式的实例化都是闭包对象,即使它们的捕获组中没有任何捕获。
      在任何其他语言(例如Python)中,闭包与lambda无关.

      C++中的闭包:由lambda表达式定义(而不是封装)的值(value),该表达式由代码以及代码中引用的变量的值组成。所以闭包是一个匿名函数对象,由编译器作为lambda表达式的结果自动创建。闭包存储lambda表达式中使用的lambda表达式定义范围内的这些变量。
      lambda表达式的运行时效果是生成对象。此类对象称为闭包。(The runtime effect of a lambda expression is the generation of an object. Such objects are known as closures)
      闭包是一个通过引用其主体外部的字段来封闭其周围状态的函数。封闭状态在闭包调用中保持不变。

      lambdas vs. Closures for C++:lambda和相应的闭包之间的区别完全等同于类和类实例之间的区别
      闭包之于lambda就像对象之于类一样(Closures are to lambdas as objects are to classes)。
      类只存在于源代码中;它在运行时不存在。运行时存在的是类类型的对象。同样地:每个lambda表达式都会导致生成一个唯一的类(在编译期间),并且还会导致创建该类类型的对象(闭包)(在运行时)。(As we know, a class exists only in source code; it doesn’t exist at runtime. What exists at runtime are objects of the class type. Similarily: Each lambda expression causes a unique class to be generated(during compilation) and also causes an object of that class type--a closure--to be created(at runtime))
      (1).例如,lambda在运行时不占用数据内存,尽管它们可能占用代码内存。
      (2).闭包占用数据内存,但不占用代码内存。

      注:以上内容主要翻译自:medium.com

      以下为测试代码:

namespace {

std::function<void(void)> closureWrapper1()
{
	int x = 10;
	return [&x]() { std::cout << "Value in the closure: " << x++ << std::endl; };
	// return [x]() mutable { std::cout << "Value in the closure: " << x++ << std::endl; };
}

} // namespace

int test_closure()
{
	// reference: https://pranayaggarwal25.medium.com/lambdas-closures-c-d5f16211de9a
	int fudgeFactor{ 6 };

	// "="右侧的表达式是lambda表达式,该表达式创建的运行时对象是闭包
	// f本身不是闭包,它是闭包的副本
	// 将闭包复制到f的过程可以优化为移动(move),但这并不能改变f本身不是闭包的事实
	auto f = [&](int x, int y) { return fudgeFactor * (x + y); };

	// 实际的闭包对象是一个临时对象,通常会在语句末尾被销毁,除非将其绑定到转发引用(forwarding reference)(也称为通用引用(universal reference))
	// 或左值引用到常量(lvalue-reference-to-const)
	auto&& rrefToClosure = [&](int x, int y) { return fudgeFactor * (x + y); };
	const auto& lrefToConstToClosure = [&](int x, int y) { return fudgeFactor * (x + y); };


	int x = 10;
	auto func0 = [&x]() { x += 1; std::cout << "Value in the closure: " << x << std::endl; };

	// func0是由其后编写的lambda表达式创建的闭包的副本
	func0();  // Value in the closure: 11

	// func1不是闭包而是一个包装闭包的std::function包装对象
	std::function<void(void)> func1 = closureWrapper1();
	func1();  // Value in the closure: 32758 // prints garbage value + 1 =~ garbage value

	return 0;
}

      执行结果如下图所示:linux下调用func1现象是段错误

      GitHubhttps://github.com/fengbingchun/Messy_Test

  • 23
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值