C++ lambda 表达式的生命周期是多长?

问题描述 投票:0回答:4

(我已经读过 C++ 中 lambda 派生的隐式函子的生命周期是多少? 已经读过,它没有回答这个问题。)

我知道 C++ lambda 语法只是用于创建带有调用运算符和某个状态的匿名类实例的糖,并且我了解该状态的生命周期要求(取决于您是否通过引用的值捕获。)但是什么是 lambda 对象本身的生命周期吗?在下面的示例中,返回的

std::function
实例有用吗?

std::function<int(int)> meta_add(int x) {
    auto add = [x](int y) { return x + y; };
    return add;
}

如果是,它是如何工作的?这对我来说似乎有点太神奇了 - 我只能想象它通过复制我的整个实例来工作,这可能会非常重,具体取决于我捕获的内容 - 过去我主要使用

std::function
和裸函数指针,复制它们很快。鉴于
std::function
的类型擦除,这似乎也有问题。
    

c++ lambda c++11
4个回答
74
投票

std::function

该对象将被创建,位于 
struct lambda { lambda(int x) : x(x) { } int operator ()(int y) { return x + y; } private: int x; }; std::function<int(int)> meta_add(int x) { lambda add(x); return add; }

函数的本地,然后将[整个对象,包括

meta_add
的值]移动到返回值中,然后本地实例将超出范围并正常销毁。但从函数返回的对象将保持有效,只要持有它的
x
对象有效。这显然取决于调用上下文。
    


18
投票
std::function

比 lambda 更困惑。


std::function

使用一种称为类型擦除的技术。这是一个快速飞行。


std::function

为什么要删除该类型?我们想要的类型不就是
class Base { virtual ~Base() {} virtual int call( float ) =0; }; template< typename T> class Eraser : public Base { public: Eraser( T t ) : m_t(t) { } virtual int call( float f ) override { return m_t(f); } private: T m_t; }; class Erased { public: template<typename T> Erased( T t ) : m_erased( new Eraser<T>(t) ) { } int do_call( float f ) { return m_erased->call( f ); } private: Base* m_erased; };

吗?


类型擦除允许的是

int (*)(float)

现在可以存储任何可调用的值,例如

Erased

int(float)



14
投票

int boring( float f); short interesting( double d ); struct Powerful { int operator() ( float ); }; Erased e_boring( &boring ); Erased e_interesting( &interesting ); Erased e_powerful( Powerful() ); Erased e_useful( []( float f ) { return 42; } );

相当于(或可以认为是):

[x](int y) { return x + y; };

所以你的对象正在返回一个看起来像那样的对象。其中有一个定义良好的复制构造函数。所以它可以正确地从函数中复制出来似乎非常合理。


6
投票

struct MyLambda { MyLambda(int x): x(x) {} int operator()(int y) const { return x + y; } private: int x; };

函数返回的 
std::function<int(int)> meta_add(int x) { auto add = [x](int y) { return x + y; }; return add; }

对象实际上保存了已分配给局部变量

std::function<int(int)>
的 lambda 函数对象的移动实例。

当您定义按值或按引用捕获的 C++11 lambda 时,C++ 编译器会自动生成唯一的函数类型,当调用 lambda 或将其分配给变量时会构造该函数类型的实例。为了说明这一点,您的 C++ 编译器可能会为

add

定义的 lambda 生成以下类类型:


[x](int y) { return x + y; }

那么,
class __lambda_373s27a { int x; public: __lambda_373s27a(int x_) : x(x_) { } int operator()(int y) const { return x + y; } };

函数本质上等价于:


meta_add

编辑:

顺便说一句,我不确定你是否知道这一点,但这是 C++11 中函数 currying 的示例。

© www.soinside.com 2019 - 2024. All rights reserved.