在C++中,而相比之下,語言,如C#,能夠指定是否與否封閉的範圍的變量應通過值或lambda表達式內的參考捕獲。這導致在其中可以未定義情況下通過與通過參考援引lambda表達式之前返回一個函數捕獲封閉範圍的λ:C++ 11:防止拉姆達範圍捕獲錯誤
void test()
{
int t = 1;
enqueue_task([&]() { do_something(t); });
}
在這種情況下,「T」,將最有可能是當由lambda表達式指定的任務計劃執行時超出範圍。顯然,這會導致醜陋的錯誤。
我的解決方案將是一個語言的功能是這樣的:
template<class T>
void enqueue_task(T lambda)
{
static_assert(!std::is_lambda<T>::value || std::is_lambda_captured_by_value<T>::value,
"The lambda expression is executed asynchronously and therefore capturing eclosing state via reference is forbidden.");
// enqueue task for execution
}
對我來說,這將是一個乾淨的「非侵入式」延伸,將允許中間件的作家,以保護他們的API被濫用。當然,它不提供防彈保護,因爲我仍然可以通過價值傳遞一個指向棧對象的指針,可能更多。無論如何,當通過值傳遞時仍然默默地導致未定義行爲的代碼本身可能已經是可疑的。
有沒有類似的東西我可以做,已經支持?
對我來說,目前一個理智的解決方案似乎在延期執行情況下不允許任何lambda表達式。例如,一個事件處理程序不應該被允許爲lambda類型。說起來容易做起來難,因爲這也意味着我不能使用std :: function並且必須返回到舊的函數類型。
一個更好的辦法是引入關鍵字的種類,如:
void test()
{
int t = 1;
enqueue_task(deferred() { do_something(t); });
}
這將確保,所有指編譯器可以,通過lambda函數將適用於延遲執行,這意味着它的封閉範圍消失了。
我認爲C++ 11已經很長的路要讓C++編程變得安全。這個拉姆達的東西是少數幾個你仍然用槍指着你的腳的地方之一。它只是一個滴答作響的時間炸彈。
「目前一個理智的解決方案似乎在延期執行情況下不允許任何lambda表達式。」那麼你失去了形成關閉的能力。 – JAB
@JAB:Ofc,但我並不是說不允許標準方式,而是API方式。因此,如果lambdas不會影響您的API的可用性,並且有可能會忘記您的API調用lambda延期,那麼您應該不使用lambdas來執行此API。 API應該強制正確使用。 – thesaint
確實如此,但它不像lambda表達式是唯一可以解決您擔心的問題的方法。如果用戶傳遞一個非lambda函數會發生一些涉及超出範圍引用的混亂情況,會發生什麼情況?或者,上帝保佑,生指針?真正強制正確使用API的唯一方法是阻止用戶提供任何類型的輸入(即使沒有這樣做,如果您不小心如何設置約束,最終可能會產生誤報,其中有效參數被拒絕,因爲它們沒有按照您的要求設置)。 – JAB