c++ lambda捕獲this 導(dǎo)致多線程下類釋放后還在使用的錯(cuò)誤問題
Lambda介紹
“Lambda表達(dá)式是現(xiàn)代C++在C ++ 11和更高版本中的一個(gè)新的語(yǔ)法糖 ,在C++11、C++14、C++17和C++20中Lambda表達(dá)的內(nèi)容還在不斷更新。 lambda表達(dá)式(也稱為lambda函數(shù))是在調(diào)用或作為函數(shù)參數(shù)傳遞的位置處定義匿名函數(shù)對(duì)象的便捷方法。通常,lambda用于封裝傳遞給算法或異步方法的幾行代碼 。
c++的lambda 可以捕獲this指針,使lambda可以在自定義的function內(nèi)使用類的成員函數(shù),這是因?yàn)椴东@this后隱式的在成員變量前加了this
但是需要注意的是,這里捕獲this,不是以一種拷貝的方式,更像是一種引用(或者別名,描述可能不準(zhǔn)確),當(dāng)在外面這個(gè)類的生命周期結(jié)束時(shí),lambda內(nèi)部還在調(diào)用這個(gè)類的成員函數(shù),那么就會(huì)出錯(cuò)
我遇到的問題是 捕獲了類A的this,對(duì)A的一個(gè)shared_ptr進(jìn)行操作。偶然會(huì)出現(xiàn)shared_ptr的內(nèi)部基類spt_count_base的報(bào)錯(cuò)。看了下這個(gè)shared_ptr 的use_count和weak_count都是0,
這就非常奇怪。shared_ptr計(jì)數(shù)是線程安全的,(但是實(shí)際指向?qū)ο蠛陀?jì)數(shù)不是原子操作),并且訪問這個(gè)sptr也加了鎖,為什么會(huì)出現(xiàn)被釋放了的情況。
大概再說下情景
class A { shared_ptr<B> sptr; sptr.func = [this](){ do something}; } class B { shared_ptr<map> sptrMap; func() { //概率崩潰 sptrMap.erase(); } }
當(dāng)A被析構(gòu)后,B注冊(cè)的回調(diào)被另一個(gè)線程調(diào)用了func();這時(shí)可能會(huì)出現(xiàn)A開始析構(gòu),剛好析構(gòu)到B,并且B的sptrMap已經(jīng)析構(gòu)時(shí),出現(xiàn)崩潰。但這個(gè)順序不是確定的無法保證,所以也不一定必出現(xiàn)這種現(xiàn)象。
防止這種現(xiàn)象可以加個(gè)判斷,在sptrMAp不為空時(shí)不進(jìn)行析構(gòu)?;蛘哂脀eak_ptr.在捕獲this前,用 weak_ptr p = std::shared_from_this;然后在lambda最開始用p.lock判斷A是否釋放
通過這個(gè)了解到了lambda捕獲的一個(gè)坑,及類析構(gòu)的順序及析構(gòu)時(shí)線程安全的保護(hù)
另附實(shí)際代碼
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(); }
運(yùn)行結(jié)果為0而非1,而且這里輸出0是未定義行為,因?yàn)樵L問的實(shí)際上是被回收的空間,只是因?yàn)榫幾g器的delete并沒有對(duì)回收的空間做額外的操作,所以p指向的仍然是原來那塊,只不過那塊已經(jīng)被unique_ptr的析構(gòu)函數(shù)自動(dòng)清除了,只不過將清除的部分全部置為0而已。
到此這篇關(guān)于c++ lambda捕獲this 導(dǎo)致多線程下類釋放后還在使用的錯(cuò)誤的文章就介紹到這了,更多相關(guān)c++ lambda捕獲this內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解析C++中不能重載為友元函數(shù)的四個(gè)運(yùn)算符
以下是對(duì)C++中不能重載為友元函數(shù)的四個(gè)運(yùn)算符進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下2013-07-07C語(yǔ)言中魔性的float浮點(diǎn)數(shù)精度問題
這篇文章主要介紹了魔性的float浮點(diǎn)數(shù)精度問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01對(duì)C++默認(rèn)構(gòu)造函數(shù)的一點(diǎn)重要說明
下面小編就為大家?guī)硪黄獙?duì)C++默認(rèn)構(gòu)造函數(shù)的一點(diǎn)重要說明。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-12-12Qt使用QCamera實(shí)現(xiàn)切換相機(jī),分辨率和圖像捕獲功能
這篇文章主要為大家介紹了如何利用Qt中的相機(jī)類QCamera,取景器類QCameraViewfinder,圖像捕獲類QCameraImageCapture實(shí)現(xiàn)切換相機(jī)、分辨率和圖像捕獲功能,需要的可以了解一下2023-04-04C++ new/delete相關(guān)知識(shí)點(diǎn)詳細(xì)解析
C語(yǔ)言用一堆標(biāo)準(zhǔn)庫(kù)函數(shù)malloc和free在自由存儲(chǔ)區(qū)中分配存儲(chǔ)空間,而C++則用new和delete表達(dá)式實(shí)現(xiàn)相同的功能2013-09-09C語(yǔ)言?模擬實(shí)現(xiàn)memcpy與memmove函數(shù)詳解
這篇文章主要介紹了C語(yǔ)言詳解如何模擬內(nèi)存函數(shù),用到了mencpy與memmove兩個(gè)函數(shù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-04-04