c++ lambda捕獲this 導致多線程下類釋放后還在使用的錯誤問題
Lambda介紹
“Lambda表達式是現(xiàn)代C++在C ++ 11和更高版本中的一個新的語法糖 ,在C++11、C++14、C++17和C++20中Lambda表達的內(nèi)容還在不斷更新。 lambda表達式(也稱為lambda函數(shù))是在調(diào)用或作為函數(shù)參數(shù)傳遞的位置處定義匿名函數(shù)對象的便捷方法。通常,lambda用于封裝傳遞給算法或異步方法的幾行代碼 。
c++的lambda 可以捕獲this指針,使lambda可以在自定義的function內(nèi)使用類的成員函數(shù),這是因為捕獲this后隱式的在成員變量前加了this
但是需要注意的是,這里捕獲this,不是以一種拷貝的方式,更像是一種引用(或者別名,描述可能不準確),當在外面這個類的生命周期結束時,lambda內(nèi)部還在調(diào)用這個類的成員函數(shù),那么就會出錯
我遇到的問題是 捕獲了類A的this,對A的一個shared_ptr進行操作。偶然會出現(xiàn)shared_ptr的內(nèi)部基類spt_count_base的報錯??戳讼逻@個shared_ptr 的use_count和weak_count都是0,
這就非常奇怪。shared_ptr計數(shù)是線程安全的,(但是實際指向對象和計數(shù)不是原子操作),并且訪問這個sptr也加了鎖,為什么會出現(xiàn)被釋放了的情況。
大概再說下情景
class A
{
shared_ptr<B> sptr;
sptr.func = [this](){ do something};
}
class B
{
shared_ptr<map> sptrMap;
func()
{
//概率崩潰
sptrMap.erase();
}
}當A被析構后,B注冊的回調(diào)被另一個線程調(diào)用了func();這時可能會出現(xiàn)A開始析構,剛好析構到B,并且B的sptrMap已經(jīng)析構時,出現(xiàn)崩潰。但這個順序不是確定的無法保證,所以也不一定必出現(xiàn)這種現(xiàn)象。
防止這種現(xiàn)象可以加個判斷,在sptrMAp不為空時不進行析構?;蛘哂脀eak_ptr.在捕獲this前,用 weak_ptr p = std::shared_from_this;然后在lambda最開始用p.lock判斷A是否釋放
通過這個了解到了lambda捕獲的一個坑,及類析構的順序及析構時線程安全的保護
另附實際代碼
using namespace std;
struct Foo {
std::unique_ptr<int> p;
std::function<void()> f() {
p.reset(new int(1));
return [=] { cout << *p << endl; };
}
};
int main() {
auto foo = new Foo();
auto f = foo->f();
delete foo;
f();
}運行結果為0而非1,而且這里輸出0是未定義行為,因為訪問的實際上是被回收的空間,只是因為編譯器的delete并沒有對回收的空間做額外的操作,所以p指向的仍然是原來那塊,只不過那塊已經(jīng)被unique_ptr的析構函數(shù)自動清除了,只不過將清除的部分全部置為0而已。
到此這篇關于c++ lambda捕獲this 導致多線程下類釋放后還在使用的錯誤的文章就介紹到這了,更多相關c++ lambda捕獲this內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
基于C語言實現(xiàn)簡單的12306火車售票系統(tǒng)
火車售票系統(tǒng)給我們的出行帶來了極大的方面,那么他基于編程是如何實現(xiàn)的呢?今天小編抽時間給大家分享一個使用C語言寫的一個簡單的火車票系統(tǒng),感興趣的朋友參考下2016-09-09
C語言中fchdir()函數(shù)和rewinddir()函數(shù)的使用詳解
這篇文章主要介紹了C語言中fchdir()函數(shù)和rewinddir()函數(shù)的使用詳解,是C語言入門學習中的基礎知識,需要的朋友可以參考下2015-09-09

