C++:lambda闭包问题,以及对一些常见结构的替换

C++:lambda闭包问题,以及对一些常见结构的替换

闭包

​ 在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是在支持头等函数的编程语言中实现词法绑定的一种技术。闭包在实现上是一个结构体 ,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。环境里是若干对符号和值的对应关系,它既要包括约束变量(该函数内部绑定的符号),也要包括自由变量(在函数外部定义但在函数内被引用),有些函数也可能没有自由变量。闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,或者理解成运行时被确定/捕获,这样即便脱离了捕捉时的上下文,它也能照常运行。捕捉时对于值的处理可以是值拷贝,也可以是名称引用,这通常由语言设计者决定,也可能由用户自行指定(就比如我们C++里面的Lambda)。

​ 通俗一点来说就是:函数是代码,状态是一组变量,将代码和一组变量捆绑,就形成了闭包,内部包含 static 变量的函数不是闭包,因为这个 static 变量不能捆绑。闭包的状态捆绑,必须发生在运行时。

lambda的内部实现

当你定义一个 lambda 时,编译器使用它来创建一个 ad-hoc 仿函数类。函子()名称是编译器生成的(可能不是任何人类可读的)

//你定义的
[](x& elem) {elem.op();}
//编译器创建的
class _SomeCompilerGeneratedName_
{
public:
  void operator() (x& elem) const
  {
    elem.op();
  }
};

lambda可以捕获上下文的变量,当你将捕获列表添加到 lambda 时,编译器会将适当的成员变量添加到 lambda-functor 类和用于初始化这些变量的构造函数。

[&total,offset](x& elem) {total +=elem.getl() + offset;}


class _SomeCompilerGeneratedName_
{
  public:
    _SomeCompilerGeneratedName_(int &t,int o) : total_{t},offset_{o} ()
    void operator() (x& elem) const {total_ += elem.getVal() + offset_;}
    
  private:
    int& total_;
    int offset_;
};

现在相对容易理解为什么捕获上下文有潜在的开销:对于每个按值捕获的对象,都会制作一个原始副本;对于通过引用捕获的每个对象,都会存储一个引用。

常用的lambda

  • 使用lambda map替代 if/else/switch
map<int, function<void()>> funcs;
funcs[1] = [](){...};
funcs[7] = [](){...};
funcs[42] = [](){...};

return funcs[x]();
//这样,就把switch/case语句转换成了function+lambda,让map替你自动switch。
  • 待补充

你可能感兴趣的:(C++,c++,开发语言)