2014-07-07 45 views
-1

因此,我一直致力於內存管理,並且在移動包含捕獲數據的lambda函數對象的對象時遇到特殊問題。假設下面的例子:更新Lambda的參考數據

typedef std::function < void(int) > funcType; 

class Something 
{ 
private: 
    int _myNum = 0; 

public: 
    funcType GetSetIt() 
    { 
     return [&] (int a) 
     { 
      _myNum = a; 
     }; 
    } 

    void SeeIt() 
    { 
     std::cout << _myNum << std::endl; 
    } 

    int GetIt() 
    { 
     return _myNum; 
    } 
}; 

而下面的操作:

auto destination = (Something*) malloc(sizeof(Something)); 
auto alt = (funcType*) malloc(sizeof(funcType)); 
auto size = sizeof(funcType); 

auto s = new Something(); 

auto setIt = s->GetSetIt(); 
setIt(10); 
s->SeeIt(); 
auto a = s->GetIt(); 

memcpy(destination, s, sizeof(Something)); 
memset(s, 0, sizeof(Something)); 

memcpy(alt, &setIt, sizeof(funcType)); 
memset(&setIt, 0, sizeof(funcType)); // point 1 

(*alt)(15); 
destination->SeeIt(); 
auto b = destination->GetIt(); 

一個快速的解釋:

創建一個新的Something並調用它的所有成員,以確保它的正常工作。然後將其移到新位置並刪除/清除它以前存在的位置。同時將函數對象移到新的位置並在之後清理。然後,使用指針到新的位置,調用函數對象和對象上的方法。

第一個問題是,一切正在順利進行,直到我memset函數對象的原始位置。如果你註釋掉該行(用// point 1註明),你會注意到它不會崩潰。

這對我來說有點奇怪,但我並不完全理解函數對象是如何在內存中佈局的,並且希望在該區域釋放一點光線。我假設,如果我將整個對象塊複製到另一個區域並清除舊空間(不刪除它,因爲它在堆棧中),它和它的所有引用都將被保留。

第二個問題,假設您已將memset行註釋掉,則「預期結果」與「預期結果」不同。我預計撥打alts上的_myNum設置爲15,就可以了。但我想更新alt的指針Something(我通常把它稱爲this指針)指向destination。我怎樣才能做到這一點?它可以在編譯器中可靠地完成嗎?我一直擔心,儘管我可以想象找到它的存儲位置並更新了值,但解決方案並不穩固,因爲lambda可以跨編譯器以各種方式實現,並且手頭可能有一些「魔術」。

對這些問題的任何幫助或洞察力都非常感謝。如果我不清楚發生了什麼,評論和我會在需要的地方提供更多細節。提前致謝!

+0

是否有一個原因,你沒有使用'new'和'delete'運算符與'operator ='一起使用?你在做什麼不是慣用的C++。 – thirtythreeforty

+0

這是在我一直在研究的內存管理器中工作情況的基本示例。我不使用'new'和'delete'有幾個原因,所以這主要是爲了說明這個概念。 –

+2

是什麼讓你認爲'將lambda寫入'std :: function'會工作?lambda可以存儲在'std :: function'中,這並不意味着它們是相同的東西,或者佈局兼容。一般來說,從'std :: function'往/從'memcpy'''發送任何東西的機會幾乎不會產生所需的行爲。 – Praetorian

回答

3

function不是可以複製的(3.9p9,9p6),因此您不能將其複製到memcpy。使用is_trivially_copyable特徵來檢測某種類型是否可以輕易複製。

如果你想從一個位置到另一個位置,使用放置新憑藉其轉移構造「移動」非平凡複製的類型的對象,並在以前的位置進行析構函數調用:

new (*buf) T(std::move(obj)); 
obj.~T(); 
0

你應該使用新的位置,並確保setter從被複制的對象中取出:

#include <functional> 
#include <iostream> 

// ... 

int main() { 
    char source[sizeof(Something)]; 
    char source_setter[sizeof(funcType)]; 
    Something* src = new (source) Something; 
    // Get the setter from the source object. 
    funcType* src_setter = new (source_setter) funcType(src->GetSetIt()); 
    (*src_setter)(0); 

    char destination[sizeof(Something)]; 
    char destination_setter[sizeof(funcType)]; 
    Something* dst = new (destination) Something(*src); 
    // Get the setter from the destination object. 
    funcType* dst_setter = new (destination_setter) funcType(dst->GetSetIt()); 
    (*dst_setter)(1); 

    src->SeeIt(); 
    dst->SeeIt(); 

    src_setter->~funcType(); 
    src->~Something(); 
    dst_setter->~funcType(); 
    dst->~Something(); 
}