2013-04-06 37 views
0

我剛剛做了一些實驗,最近使用了函數式響應式編程,它是什麼,當我試圖在C++中實現類似的東西時,我轉向lambda尋求幫助。我想出了這樣的開始,lambda和他們的捕獲值

template<class T> 
class Reactive 
{ 
public: 
    Reactive(T data) 
    { 
     m_Data = data; 
    } 

    Reactive(std::function<T()> func, T data) 
    { 
    m_Data = data; 
    m_Affecter = func; 
    } 

    template<class H> 
    Reactive & operator+(const H & rhs) 
    { 
     m_Data += rhs; 

     return *this; 
    } 

    template<class H> 
    Reactive operator+(Reactive<H> & rhs) 
    { 
    std::function<decltype(m_Data + rhs.m_Data)()> func; 

    if (!rhs.m_Affecter) 
     func = [&](){return m_Data + rhs.m_Data;}; 
    else 
     func = [&](){return m_Data + rhs.m_Affecter();}; 

    return Reactive<decltype(m_Data + rhs.m_Data)> (func, m_Data + rhs.m_Data); 
    } 

    Reactive & operator=(const T & data) 
    { 
     m_Data = data; 

     return *this; 
    } 

    Reactive & operator=(const Reactive & rhs) 
    { 
     m_Data = rhs.m_Data; 
     m_Affecter = rhs.m_Affecter; 

     return *this; 
    } 

    T & Get() 
    { 
     return m_Data; 
    } 

    void Update() 
    { 
     m_Data = m_Affecter(); 
    } 

private: 
    std::function<T()> m_Affecter; 
    T m_Data; 
}; 

它只支持添加到目前爲止。我試圖創建一個名爲被動對象的對象,它可以圍繞任何其他類型進行封裝,除了當對其執行數學運算時,會創建一個lambda,並在那裏進行該操作,以便記住所做的事情並在其中一個影響值發生變化時再次執行(在調用更新函數之後)。例如,如果我要這樣做。

Reactive<int> cheh = 0; 
Reactive<int> meh = 3; 
Reactive<int> peh = 7; 
cheh = meh + peh; 
meh = meh + 4; 
cheh.Update(); 
std::cout << cheh.Get(); 

然後繼承人會發生什麼。總結第五行中的兩個Reactives將使另一個Reactive與它們的兩個值相加爲10,並將它的影響器設置爲做類似這樣的lambda,& {meh.m_Data + peh.m_Data}。那Reactive就會分配給cheh。當m_meh的值增加了4,cheh被更新時,它的影響力被調用,新的值爲14,這就是打印到屏幕上的內容,完全按照我的意圖。

但是後來我開始思考,如果參與cheh的影響者的Reactives中的一個退出範圍會怎樣。如果處理不正確,程序應該會出錯。 所以我這樣做,

Reactive<int> cheh = 0; 
Reactive<int> meh = 3; 

{ 
    Reactive<int> peh = 7; 
    cheh = meh + peh; 
    peh = peh + 4; 
} 

cheh.Update(); 
std::cout << cheh.Get(); 

在更新時調用點,發生在他affecter無功正常皮膚已經超出了範圍,不再存在。然而,這個程序和cheh的影響者成功執行,並且像以前一樣打印出14個。我知道lambda中的值是通過引用捕獲傳入的,那麼,受害者函數如何仍然可以訪問引用peh?通過引用傳遞給lambda表達式的對象或整型類型是否強制它們在lambda存在時一直存在?有東西聞起來很腥......

回答

3

我知道lambda中的值是通過引用捕獲傳入的,所以如何讓影響者函數仍然可以訪問對引用的引用?通過引用傳遞給lambda表達式的對象或整型類型是否強制它們在lambda存在時一直存在?有東西聞起來很腥......

該程序有未定義的行爲。如您懷疑的那樣,通過引用捕獲而不是延長這些引用綁定到的對象的生命週期,並且取消引用不再存在的對象的引用是UB。

但是,未定義的行爲並不一定意味着會發生崩潰。這是可能的(似乎是這種情況),程序將只是似乎工作正常。這可能不是在另一臺計算機上,或重新啓動機器後。

另請參閱this brilliant explanation爲什麼看起來物體在超出範圍之後可能會被訪問​​。

+0

看起來不像是這樣,但這實際上是個好消息。聽起來好像調試會很糟糕,如果lambda強迫它繼續存在的話。我會建立一個信號插槽系統,通知Reactives當其他反應參與那裏影響者被破壞,這將影響零。 Thankee親切! – FatalCatharsis 2013-04-06 17:13:16

+0

@FatalCatharsis:很高興幫助:) – 2013-04-06 17:16:17