C++面经 : C++ 11 新特性(闭包与匿名函数) ----C++ Closure & C++ anonymous functions

关于C++ Closure 闭包 和 C++ anonymous functions 匿名函数

  • 什么是闭包?

  在C++中,闭包是一个能够捕获作用域变量的未命名函数对象,它包含了需要使用的“上下文”(函数与变量),同时闭包允许函数通过闭包的值或引用副本访问这些捕获的变量,即使函数在其范围之外被调用。

在维基百科中,闭包在程序语言中的定义:In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functionsOperationally, a closure is a record storing a function[a] together with an environment.[1] The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created.[b] Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

维基百科原文👉Closure (computer programming) - Wikipedia

 

  • 什么是匿名函数?

  匿名函数(也被称作lambda 抽象/表达式/函数)是一种没有被绑定标识符的函数,可以用于很方便地定义一个临时的函数对象,或作为一个函数对象传递给更上层的函数。在维基百科中解释为:In computer programming, an anonymous function (function literallambda abstractionlambda functionlambda expression or block) is a function definition that is not bound to an identifier. Anonymous functions are often arguments being passed to higher-order functions or used for constructing the result of a higher-order function that needs to return a function.[1] If the function is only used once, or a limited number of times, an anonymous function may be syntactically lighter than using a named function. Anonymous functions are ubiquitous in functional programming languages and other languages with first-class functions, where they fulfil the same role for the function type as literals do for other data types.

维基百科原文👉匿名功能 - 维基百科 (wikipedia.org)

  在C++ 中从C++ 11 标准后,引入了匿名函数的概念。

型如:

[capture](parameters) -> return_type { function_body }

C++11 还支持闭包,此处称为捕获。捕获在 lambda 表达式声明中的方括号之间定义。该机制允许按值或引用捕获这些变量。下表对此进行了说明:[]

[]        // No captures, the lambda is implicitly convertible to a function pointer.
[x, &y]   // x is captured by value and y is captured by reference.
[&]       // Any external variable is implicitly captured by reference if used
[=]       // Any external variable is implicitly captured by value if used.
[&, x]    // x is captured by value. Other variables will be captured by reference.
[=, &z]   // z is captured by reference. Other variables will be captured by value.

 

匿名函数可以替代掉复杂且冗余的仿函数,使得代码更易于理解和维护:

sort(foo.begin(), foo.end(), [](const Foo& f1, const Foo& f2)
{
    return f1.a_ != f2.a_ ? f1.a_ > f2.a_ : f1.b_ > f2.b_;
});

匿名函数由以下几个部分组成,其中只有 1, 2, 6 三个部分是必须的,其余部分可以省略:

 

  1. 捕获子句 capture clause / lambda introducer
  2. 参数列表 parameter list / lambda declarator
  3. 可变规格 mutable specification
  4. 被 mutable 修饰的匿名函数可以修改按值捕获的变量
  5. 异常规格 exception specification
  6. 尾随返回类型 trailing-return-type
  7. 匿名函数体 lambda body

闭包在匿名函数的实现:

捕获子句用于捕获外部变量,使得匿名函数体可以使用这些变量,捕获的方法分为引用捕获和值(拷贝)捕获两种,使用方法如下:

  1. [] 不捕获任何变量;
  2. [&] 按引用捕获所有外部变量;
  3. [=] 按值捕获所有外部变量
  4. [&, var] 默认按引用捕获,仅按值捕获 var;
  5. [=, &var] 默认按值捕获,仅按引用捕获 var;
  6. [y, y] 重复按值捕获同一个变量,没有意义,会报 warning;
  7. [&, &var] 默认按引用捕获,并按引用捕获 var,没有意义,会报 warning;
  8. [=, this] 默认按值捕获,并按值捕获 this 指针,没有意义,同样会报 warning;

在使用捕获子句的时候,需要注意一些问题:

  1. 不建议使用 2,3 这两种方式进行捕获(对性能影响较大),应该明确地指出需要按引用捕获的变量;
  2. 按值捕获的变量是 read-only (const) 的,只有当匿名函数的可变规格被显式声明为 mutable 的时候才可以修改按值捕获的变量;

 

参考 知乎原文连接👉C++ 闭包和匿名函数 - 知乎 (zhihu.com)

posted @ 2022-11-15 11:18  slowlydance2me  阅读(535)  评论(0编辑  收藏  举报