2011-11-28 109 views
3

我想使用lambda函數來異步調用引用計數對象的一個​​方法:LAMBDA爲std ::函數轉換性能

void RunAsync(const std::function<void()>& f) { /* ... */ } 

SmartPtr<T> objPtr = ... 
RunAsync([objPtr] { objPtr->Method(); }); 

創建lambda表達式明顯創建一個副本,但我現在有將lambda表達式轉換爲std::function對象的問題也會創建一堆我智能指針的副本,並且每個副本都會增加引用計數。

下面的代碼應該表現出這種行爲:

#include <functional> 

struct C { 
    C() {} 
    C(const C& c) { ++s_copies; } 

    void CallMe() const {} 

    static int s_copies; 
}; 

int C::s_copies = 0; 

void Apply(const std::function<void()>& fct) { fct(); } 

int main() { 
    C c; 
    std::function<void()> f0 = [c] { c.CallMe(); }; 
    Apply(f0); 
    // s_copies = 4 
} 

雖然引用的數量恢復到正常的事後,我想,以防止過多的引用操作的性能的原因。我不確定所有這些複製操作來自哪裏。

有什麼辦法可以用我的智能指針對象的較少副本來實現這一點?

更新:編譯器是Visual Studio 2010中

+0

很多副本有什麼不好?一個智能指針的副本是兩個指針的副本和一個數字的增量...不是爲了殺死性能 – Dani

+3

爲什麼你不通過引用捕獲?正如'[&c] {c.CallMe(); };'和智能指針一樣。 ' – Nawaz

+2

@Dani:在許多引用計數的智能指針中,算術是原子的,因此需要更多的開銷。 –

回答

5

std::function爲自定義函數對象,直到編譯器實現的簡單的情況下一些嚴重的特殊待遇可能不會那麼快。

但是,引用計數問題是適合move時複製的症狀。正如其他人在評論中指出的那樣,MSVC沒有正確實施move。你所描述的用法只需要移動,而不是複製,所以引用計數不應該被觸及。

如果可以,請嘗試使用GCC編譯並查看問題是否消失。

+0

不幸的是,我無法編譯GCC中的整個項目,但我的演示代碼在GCC中的行爲與預期相同。所以,如果我理解正確的問題不是lambda表達式,而是''std :: function''實現?在std :: bind中使用'std :: function''時,看起來好像我有相同的(或更糟糕的)問題。 – fschoenm

+0

此外,我曾經有一個自定義的函數實現,我想用''std :: function''來替換它,而不顯示這種行爲。似乎我還無法擺脫它。 – fschoenm

+0

@fschoenm我不使用Windows,但James McNellis在微軟工作,所以您可以在評論中嘗試他的建議。嘗試用原始函數指針替換'std :: function',因爲lambda函數也會將其轉換爲該函數。 – Potatoswatter

2

轉換爲std::function應該只會使拉姆達的舉動。如果這不是所做的事情,那麼可以說在執行或規範std::function中存在一個錯誤。另外,在上面的代碼中,我只能看到兩個原始c的副本,一個創建lambda,另一個創建它的std::function。我看不到額外的副本來自哪裏。

+0

我忘了提及我正在使用Visual Studio 2010.在GCC中,我也只獲得兩個副本(如果我實現了一個移動構造函數,則只有一個副本)。 – fschoenm

相關問題