簡體   English   中英

C ++ lambda表達式的生命周期是多少?

[英]What is the lifetime of a C++ lambda expression?

(我已經閱讀了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裸函數指針,復制它們很快。 鑒於std::function的類型擦除,它似乎也有問題。

如果用手動編織器代替lambda,它的生命周期正是如此:

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函數的本地創建,然后[在其entirty中,包括x的值]移動到返回值中,然后本地實例將超出范圍並正常銷毀。 但是只要保存它的std::function對象,從函數返回的對象將保持有效。 這多長時間顯然取決於調用上下文。

看起來你對std::function比lambdas更困惑。

std::function使用一種名為type-erasure的技術。 這是一個快速飛過。

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)

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; };

相當於:(或者也可以考慮)

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)>返回的std::function<int(int)>對象實際上包含已分配給局部變量add的lambda函數對象的移動實例。

當您定義捕獲按值或按引用的C ++ 11 lambda時,C ++編譯器會自動生成一個唯一的函數類型,其實例是在調用lambda或賦值給變量時構造的。 為了說明,您的C ++編譯器可能會為[x](int y) { return x + y; }定義的lambda生成以下類類型[x](int y) { return x + y; } [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函數基本上等同於:

std::function<int(int)> meta_add(int x) {
    __lambda_373s27a add = __lambda_373s27a(x);
    return add;
}

編輯:順便說一句,我不知道你是否知道這一點,但這是C ++ 11中函數currying的一個例子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM