c++ 11 lambda -为什么我需要捕获自动持续时间变量
C++11 lambda - why do I need to capture auto duration variables?
当在捕获'[]'部分编写lambda函数时,我需要只指定自动持续时间变量,而全局和静态变量在lambda函数中使用而不需要捕获。为什么呢?为什么我们不能像使用全局和静态变量一样使用自动持续时间变量?
因为lambda定义了一个单独的作用域:它相当于:
int global_i;
struct Lambda {
Lambda(int captured_j) : captured_j(captured_j) {}
void operator()(){
// in this scope, global_i is accessible, and by capturing auto_j, we make that visible as well, but we can't see auto_i
}
int captured_j;
}
void foo() {
int auto_i;
int auto_j
// this lambda
[j](){}
// is just shorthand for this:
Lambda lambda(j);
}
lambda被编译器转换成一个函数对象(就像我的例子中的Lambda
类)。并且函数对象不能访问在函数对象实例化的作用域中声明的局部变量。除非你通过将它们传递给构造函数来"捕获"它们。
至于为什么编译器不隐式地这样做,不需要你提示它,因为它不知道你是想按值捕获还是按引用捕获。在GC语言中,您总是通过引用捕获,因为这无关紧要——只要您需要,您引用的对象就会一直存在。
但是在c++中,您需要管理这些对象的生命周期,如果lambda总是通过引用捕获,那么它在声明它的作用域之外实际上是无用的(因为它将包含对已被销毁的对象的引用)。因此,在c++中,必须指定是要按值捕获还是按引用捕获。因为你必须指定,编译器不能直接为你做
考虑这个简单的函数:
std::function<foo()> f()
{
foo afoo;
return [=](){ return afoo; };
}
int main()
{
auto l = f();
l();
}
如果不捕获变量afoo
,那么在lambda形成的闭包被使用之前,它就会超出作用域!
还请注意,我使用按值捕获完全是出于同样的原因:返回指向局部变量的引用/指针具有未定义的行为。
实际上,lambda并没有什么神奇之处;简单地把它看作一个匿名函子。
传统的函子也不知道它所在的局部变量,你需要把它们提供给它的函数。像lambda这样的匿名对象没有可自定义的c'tor,因此您可以通过这种"[]"语法提供上下文。
或者考虑
const float g_foo = 42.f;
struct A {
float _bar;
struct B {
B() : _baz(_bar /*oops*/) {}
float _baz;
};
};
在A::B的闭包中没有A的"_bar"的概念,但是g_foo是已知的。
相关文章:
- 从持续时间构造std::chrono::system_clock::time_point
- 我有一个对象,它将在整个程序的持续时间内实例化,但一个类成员不会,我应该动态分配它吗?
- 时间持续时间到时间字符串
- 指向(数据)成员的指针作为非类型模板参数,例如具有自动存储持续时间/无链接
- 为什么具有静态存储持续时间的同一内联变量在包含在 VS2017 编译的两个翻译单元中时会构造和销毁两次
- 将毫秒转换为给定格式的持续时间
- 具有静态存储持续时间的常量初始化变量的初始化顺序
- 划分和乘以STD :: Chrono ::持续时间
- 静态存储持续时间初始化
- C++计划持续时间内(字体)资源的分配
- FFMPEG:具有不同持续时间的多路复用流
- 在不同翻译单元中具有静态存储持续时间的依赖非局部常量浮点变量的常量初始化
- 使用System_Clock :: TO_TIME_T警告持续时间_t
- 访问和存储/解析性std :: Chrono ::持续时间:: milliseconds(cpprest)时使用什么类型
- 我可以让QT到概要文件插槽执行持续时间吗?
- 在STD :: Chrono ::剩余时间测量的持续时间
- 自定义 AVIOContext 的未定义 AVFormatContext 持续时间
- C++ - 函数中的局部指针变量具有什么类型的存储持续时间以及它们存储在哪里?
- 是块作用域静态或线程存储持续时间变量初始化失败的原因
- c++ 11 lambda -为什么我需要捕获自动持续时间变量