2012-04-27 119 views
4

我有一個程序,我不能使用標準std::async和線程機制。相反,我必須像這樣編寫程序:使用lambda作爲異步回調

void processor(int argument, std::function<void(int)> callback) { 
    int blub = 0; 

    std::shared_ptr<object> objptr = getObject(); 

    // Function is called later. 
    // All the internal references are bound here! 
    auto func = [=, &blub]() { 
    // !This will fail since blub is accessed by reference! 
    blub *= 2; 

    // Since objptr is copied by value it works. 
    // objptr holds the value of getObject(). 
    objptr->addSomething(blub); 

    // Finally we need to call another callback to return a value 
    callback(blub); 
    }; 

    objptr = getAnotherObject(); 

    // Puts func onto a queue and returns immediately. 
    // func is executed later. 
    startProcessing(func); 
} 

現在我想知道我是否做對什麼用lambda表達式作爲異步回調是最好的方式。

編輯:添加預期的行爲代碼評論。 請參閱blub的問題的可能解決方案的回答/評論。

+1

那是含糊不清的。回答諸如「做X的最佳方式」這樣的問題很難。你可以使用lambdas作爲回調。還有什麼事情你需要知道? – jalf 2012-04-27 11:16:43

+0

'blub'已經不存在了,在labda執行時對它的引用不應該是有效的,對嗎? – 2012-04-27 11:18:55

+0

基本上,有趣的是,異步如何與對象的生命週期和範圍確定一起工作。我讀的所有信息都是通過使用lambda同步 - 無法找到任何異步。 – abergmeier 2012-04-27 11:19:54

回答

4

函數對象將包含對局部變量blub的引用。 與語言中的其他情況一樣,在函數結束後,這不會使局部變量生效。

所有其他捕獲的對象的副本將存儲在函數對象中,因爲它們是按值捕獲的。這意味着他們沒有問題。

如果您希望在功能結束後使用它,您不能將其使用期限與功能綁定:您需要動態存儲時間。一個std::unique_ptr可用於處理此類對象的清理,但它變得有點討厭,因爲你不能「捕獲通過移動」爲lambda:S

auto blub = make_unique<int>(0); // [1] 

std::shared_ptr<object> objptr = getObject(); 

// use std::bind to store the unique_ptr with the lambda 
auto func = std::bind([=](std::unique_ptr<int>& blub) { 
    *blub *= 2; 

    objptr->addSomething(*blub); 

    callback(*blub); 
}, std::move(blub)); // move the unique_ptr into the function object 

objptr = getAnotherObject(); 

// func is not copiable because it holds a unique_ptr 
startProcessing(std::move(func)); // move it 

作爲一個補充說明,舊的棄用的std::auto_ptr在這裏實際上可以正常工作,因爲如果lambda通過值捕獲它,它將被複制,並且其奇怪的複製語義正是需要的。


1. make_uniqueGOTW #102

+0

看看媽媽,不要'新'! – 2012-04-27 21:37:53

+1

在我看來,應該以規則結束,您應該總是通過使用'std :: shared_ptr'並通過值傳遞它們來訪問lambda之外的內容。然後這會消除對「std :: bind」調用的需要。如果你確實有blub作爲一個對象,然後想把它移動到lambda中,使用'std :: bind'會使IMO有意義。 – abergmeier 2012-04-28 17:57:28

+1

@LCIDFire是的,這聽起來像一個很好的規則。我在這裏使用綁定,因爲'blub'是一個局部變量,它不可能被共享。 – 2012-04-29 01:46:16