簡體   English   中英

std :: functions和lambda函數傳遞

[英]std::functions and lambda function passing

我有一個類,它將std::function作為參數,我分配了一個lambda函數。 它在構造函數中工作,但之后停止工作。 調試器在運行第一行后表示f為“空”。 為什么?

#include <iostream>
#include <string>
#include <functional>

typedef std::function<void(std::string)> const& fn;

class TestClass
{
public:
    TestClass(fn _f) : f(_f) { F(); }
    void F() { f("hello"); };

private:
    fn f;
};


int main()
{
    TestClass t([](std::string str) {std::cout << str << std::endl; });

    t.F();

    return 0;
}

調用tF()會導致錯誤。 為什么?

我可以通過將其更改為以下內容來解決此問題:

int main()
{
    fn __f = [](std::string str) {std::cout << str << std::endl; };
    TestClass t(__f);

    t.F();

    return 0;
}

但是,當我將fn更改為auto時,這不起作用!

int main()
{
    auto __f = [](std::string str) {std::cout << str << std::endl; };
    TestClass t(__f);

    t.F();

    return 0;
}

為什么會發生這種情況的原因是什么?

注意(1) fn定義為引用 (對const); (2)lambda和std::function的類型不一樣; (3)您不能直接綁定對不同類型的對象的引用。

對於第一種情況,

TestClass t([](std::string str) {std::cout << str << std::endl; });
t.F();

創建一個臨時lambda,然后轉換為std::function ,這也是一個臨時的。 臨時std::function綁定到構造std::function的參數_f並綁定到成員f 在此聲明之后,臨時將被銷毀,然后當tF();f變為懸空tF(); 它失敗。

對於第二種情況,

fn __f = [](std::string str) {std::cout << str << std::endl; };
TestClass t(__f);
t.F();

創建臨時lambda然后綁定到引用(到const)。 然后它的生命周期延長到引用__f的生命周期,所以代碼很好。

對於第三種情況,

auto __f = [](std::string str) {std::cout << str << std::endl; };
TestClass t(__f);
t.F();

創建lambda然后轉換為std::function ,這是一個臨時的。 臨時std::function綁定到構造std::function的參數_f並綁定到成員f 在此聲明之后,臨時將被銷毀,然后當tF();f變為懸空tF(); 它失敗。


(1)你可以將fn聲明為非引用,如typedef std::function<void(std::string)> fn; ,然后將復制std::function並且每個案例都能正常工作。
(2)不要使用以雙下划線開頭的名稱,它們是在C ++中保留的。

typedef std::function<void(std::string)> const& fn;

這不是std::function ,它是對std::function的引用。

TestClass(fn _f) : f(_f) { F(); }
fn f;

在這里,你將一個const&一個std::function綁定到另一個const&一個std::function 構造函數體中的F()起作用,因為引用至少與構造函數一樣有效。

TestClass t([](std::string str) {std::cout << str << std::endl; });

這將創建一個從lambda創建的std::function臨時文件。 這個臨時持續時間與當前行一樣長(直到; )。

然后丟棄臨時std::function

由於TestClass通過const&獲取std::function ,因此它不會延長臨時生命周期。

所以在行之后,對std::function const&任何調用都是未定義的行為,你在稍后調用.F()會看到這種行為。

fn __f = [](std::string str) {std::cout << str << std::endl; };

這確實參考了壽命延長。 從lambda創建的臨時std::function的生命周期延長到__f變量的生命周期。

順便說一句,這一行也會使你的程序形成錯誤,不需要診斷,因為它有一個包含雙下划線的變量。 這些標識符保留用於編譯器的實現,您可能無法創建它們。

TestClass t(__f);

然后我們傳遞這個引用(指的是生命周期擴展臨時),一切正常。

auto __f = [](std::string str) {std::cout << str << std::endl; };

這會創建一個變量__f (參見上面的錯誤名稱),它是一個lambda。

lambda不是std::function 可以隱式地從lambda創建std::function

TestClass t(__f);

這將從lambda創建一個臨時的std::function ,將其傳遞給TestClass構造函數,然后銷毀臨時的。

在此行之后,對.F()的調用最終會在懸空引用之后,並且會導致未定義的行為。

你的核心問題可能是你認為lambda是一個std::function 它不是。 std::function可以存儲lambda。

你的第二個問題是將某個東西定義為const& ,這幾乎總是一個非常愚蠢的想法。 引用的行為與基本方式的值不同。

您的第三個問題是變量名稱中的雙重修正。 (或以_后跟大寫字母開頭的標識符)。

如果你想知道std::function如何工作以及它是什么,那么在這個主題上有很多好的SO帖子,有各種級別的技術細節。

暫無
暫無

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

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