最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++?smart?pointer全面深入講解

 更新時(shí)間:2022年08月25日 08:37:51   作者:殺神李  
一般在C/C++中,如果我們使用了pointer來指向某塊heap區(qū)域,當(dāng)不再需要這塊區(qū)域的時(shí)候,我們需要手動刪除它。如果忘了的話,就會產(chǎn)生memory?leak

我們?yōu)槭裁葱枰猻mart pointer

眾所周知 新手寫的c++代碼是很恐怖 壓根就不能用 其中最大的原因就在于新手寫的代碼可能存在大量的內(nèi)存泄漏 那么為什么新手無法很好的去掌握內(nèi)存的東西呢 就是因?yàn)樵腸++并不像java那樣存在垃圾回收的機(jī)制 申請?jiān)诙褏^(qū)的資源都需要自己去回收 然而最痛苦的一件事情在于 指針的生命周期結(jié)束時(shí) 你會不小心就沒去回收他在堆區(qū)的資源 因?yàn)槎褏^(qū)資源的生命周期是很難把握的 有可能你析構(gòu)了 直接導(dǎo)致野指針訪問異常那么為了解決這個(gè)問題 c++就推出了智能指針 其中最重要的三種指針就是shared_ptr unique_ptr weak_ptr 接下來讓我們來講講如何將智能指針的生命周期和堆區(qū)資源的生命周期綁定起來吧

其實(shí)也非常簡單 本質(zhì)就是當(dāng)這片堆區(qū)資源的引用計(jì)數(shù)變?yōu)?的時(shí)候就釋放這片內(nèi)存

smart pointer基本概念之引用計(jì)數(shù)

先來說說引用計(jì)數(shù) 這個(gè)東西是stl保證了肯定是線程安全的 所以即使你在多個(gè)線程內(nèi)同時(shí)去增加或者同時(shí)減少引用計(jì)數(shù)也并不會讓引用計(jì)數(shù)的值出現(xiàn)非你預(yù)期的結(jié)果

智能指針是和引用計(jì)數(shù)綁定在一起的 當(dāng)你創(chuàng)建智能指針指向一片資源時(shí) 引用計(jì)數(shù)就加一 當(dāng)智能指針析構(gòu)時(shí) 引用計(jì)數(shù)就減一 當(dāng)引用計(jì)數(shù)變?yōu)?時(shí) 堆區(qū)資源被析構(gòu)

smart pointer之shared_ptr

讓我們來看看下一段代碼

int main()
 {
	std::shared_ptr<std::string> i(new std::string("its good"));
	std::shared_ptr<std::string> j(new std::string("its bad"));
	std::vector<std::shared_ptr<std::string>> smartPointer_vec;
	for(int k=0;k<5;k++)
	smartPointer_vec.emplace_back(i);
	for (int k = 0; k < 4; k++)
	smartPointer_vec.emplace_back(j);
	for (auto &i : smartPointer_vec)
	{
		std::cout<<i->c_str();
		std::cout << i.use_count() << " ";
		std::cout << j.use_count() << std::endl;
		i = nullptr;
	}
	std::cout << i->c_str();
	std::cout << i.use_count() <<" ";
	std::cout << j.use_count() << std::endl;
}

聰明人看輸出 你就能完全明白 當(dāng)引用計(jì)數(shù)為0的時(shí)候就會析構(gòu) 其他不多說了

重要講解:首先使用share_ptr去指向new出來的數(shù)據(jù)是性能低效的 最本質(zhì)的原因在于 他會進(jìn)行兩次內(nèi)存分配 第一次是對象堆區(qū)資源的申請 然后才是引用計(jì)數(shù)堆區(qū)資源的申請 而使用make_shared可以只進(jìn)行一次內(nèi)存分配 所以他更快 并且更安全 并且c++標(biāo)準(zhǔn)委員會也推薦你這么做 關(guān)于make_shared等下講解

自定義deleter(也就是自定義刪除器)

先說我們?yōu)槭裁葱枰远x刪除器 因?yàn)樵谀承┣闆r下 我們希望當(dāng)智能指針指向的堆區(qū)資源釋放的時(shí)候進(jìn)行一些自定義操作也就是說你可以玩一些很花的操作 但是也是那句話 stl并不會執(zhí)行任何安全檢查 崩了需要自己負(fù)責(zé)并且總所周知 new []這種形式的堆區(qū)資源需要我們使用delete[]來釋放 這就是最大的問題 shared_ptr默認(rèn)是使用delete的 也就是說 當(dāng)你使用shared_ptr去指向new []時(shí)如果不自定義刪除器 必然會造成內(nèi)存泄漏 如下圖所示的一段代碼就是經(jīng)典的內(nèi)存泄漏

正確的寫法如下

即自定義一個(gè)刪除器 當(dāng)然你也可以玩一些移動操作 也就是花哨的操作 當(dāng)然花哨操作就很多了 我只演示其中一種如下圖所示

運(yùn)行結(jié)果截圖如下:

Tips:當(dāng)你非常清楚你在干什么的時(shí)候再玩 功力不夠 不要亂玩

shared_ptr之make_shared

上文我們說過 使用智能指針指向new出來的資源有一個(gè)問題就是他會進(jìn)行兩次內(nèi)存分配 而標(biāo)準(zhǔn)委員會推薦創(chuàng)建shared_ptr的方式是使用make_shared 讓我們來看看make_shared是如何進(jìn)行堆區(qū)資源申請的 一個(gè)最簡單的例子如下

int main()
{
	std::shared_ptr<int>p1(new int(5));
	//下面這種方式比上面這種方式性能更快 并且更加安全
	std::shared_ptr<int>p2 = make_shared<int>(5);
}

當(dāng)你使用make_shared的時(shí)候 又想去使用智能指針指向一個(gè)數(shù)組的時(shí)候 一個(gè)推薦的做法如下

int main()
{
	std::shared_ptr<std::vector<int>>p1(new std::vector<int>());
	//下面這種方式比上面這種方式性能更快 并且更加安全
	std::shared_ptr<std::vector<int>>p2 = make_shared<std::vector<int>>();
}

智能指針存在的問題之循環(huán)引用

那么現(xiàn)在我們來看看shared_ptr存在的一些問題 其中比較著名的一個(gè)問題就是循環(huán)引用 什么叫循環(huán)引用呢 本人的觀點(diǎn)是當(dāng)你的智能指針指向的A堆區(qū)資源里又有智能指針去指向B堆區(qū)資源 而B堆區(qū)資源又存在一個(gè)智能指針來指向A堆區(qū)資源 而你能拿到的指針對半是全局或者是棧區(qū)的智能指針 你無法干預(yù)到堆區(qū)的智能指針的釋放 下面來看一個(gè)最簡單的例子造成的循環(huán)引用 代碼如下圖所示

class SmartPointerTest
{
public:
	std::shared_ptr<SmartPointerTest> LoopRef{};
	int p[1000]{};
};
int main()
{
	std::shared_ptr<SmartPointerTest>p1(new SmartPointerTest());
	std::shared_ptr<SmartPointerTest>p2(new SmartPointerTest());
	p1->LoopRef = p2;
	p2->LoopRef = p1;
}

可以明顯看到 我們創(chuàng)建了兩個(gè)智能指針p1和p2 而p1指向的堆區(qū)資源里又有智能指針指向p2的堆區(qū)資源 同理p2 而當(dāng)main函數(shù)結(jié)束的時(shí)候 p1 p2指針被釋放 但是 這個(gè)時(shí)候 因?yàn)閮善褏^(qū)資源的引用計(jì)數(shù)都沒被置為0 所以不會釋放 那么這片堆區(qū)內(nèi)存也就永遠(yuǎn)的泄漏了 這是所有循環(huán)引用的原型 無論任何再復(fù)雜的循環(huán)引用都是建立在這個(gè)最基本的循環(huán)引用之上的

解決循環(huán)引用之weak_ptr

我們現(xiàn)在希望有一個(gè)方法來解決循環(huán)引用的問題 并且我們也想去隨時(shí)拿到資源 那么我們該如何做呢 標(biāo)準(zhǔn)委員會也考慮到了這個(gè)問題 于是他提供了weak_ptr 當(dāng)他指向一片堆區(qū)資源的時(shí)候 并不會讓這片堆區(qū)資源的引用計(jì)數(shù)加一 而是作為這片資源的觀察者 當(dāng)需要這片資源的時(shí)候 隨時(shí)使用lock()函數(shù)來獲得一個(gè)shared_ptr來進(jìn)行使用 下面讓我們來看看如何使用weak_ptr 基于上面的例子

class SmartPointerTest
{
public:
	std::weak_ptr<SmartPointerTest> LoopRef{};
	int p[1000]{};
};
int main()
{
	std::shared_ptr<SmartPointerTest>p1(new SmartPointerTest());
	std::shared_ptr<SmartPointerTest>p2(new SmartPointerTest());
	p1->LoopRef = p2;
	p2->LoopRef = p1;
	//當(dāng)你想使用資源的時(shí)候 用下面的操作進(jìn)行
	std::cout << p1->LoopRef.lock()->p << std::endl;
}

輸出結(jié)果如下:

Tips:當(dāng)然weak_ptr的作用遠(yuǎn)遠(yuǎn)不止如此 他存在的意義僅僅是你想共享資源但是你并不想增加引用計(jì)數(shù) 解決循環(huán)引用只是順便解決的優(yōu)秀的程序員總是能知道在什么情況下使用何種指針來達(dá)到性能最優(yōu) lock()函數(shù) 顧名思義是要去給引用計(jì)數(shù)上鎖的 頻繁上鎖帶來的性能問題不用多說了吧

如果weak_ptr指向的資源已經(jīng)被析構(gòu) 那么他會拋出bad_weak_ptr的異常 請注意捕獲異常

智能指針問題

無法創(chuàng)建指向自己的智能指針(本質(zhì)當(dāng)創(chuàng)建自己的智能指針時(shí)會創(chuàng)建兩個(gè)所屬組)

什么叫無法創(chuàng)建指向自己的智能指針呢 看如下這段代碼

class SmartPointerTest
{
public:
	std::weak_ptr<SmartPointerTest> LoopRef{};
	int p[1000]{};
	std::vector<std::shared_ptr<SmartPointerTest>> spt_vec;
	void MemberFuncTest()
	{
		spt_vec.push_back(std::shared_ptr<SmartPointerTest>(this));
	}
	int operator[](int i)
	{
		return p[i];
	}
};
int main()
{
	std::shared_ptr<SmartPointerTest>p1(new SmartPointerTest());
	p1->MemberFuncTest();
	std::cout<<p1.use_count()<<std::endl;
	system("pause");
}

我們預(yù)期的結(jié)果是把指向自己的智能指針傳入 并且引用計(jì)數(shù)為2 但是運(yùn)行結(jié)果如下:

并且程序會崩潰 為什么呢 因?yàn)槟阒貜?fù)釋放了 這就是我說的 你會創(chuàng)建兩個(gè)組 而不是單純的增加引用計(jì)數(shù) 其本質(zhì)還是濫用普通指針和智能指針引起的麻煩

解決方法如下

代碼如下 我們可以繼承于std::enable_shared_from_this來解決

class SmartPointerTest :std::enable_shared_from_this<SmartPointerTest>
{
public:
	std::weak_ptr<SmartPointerTest> LoopRef{};
	int p[1000]{};
	std::vector<std::shared_ptr<SmartPointerTest>> spt_vec;
	void MemberFuncTest()
	{
		spt_vec.push_back(std::shared_ptr<SmartPointerTest>(shared_from_this()));
	}
	int operator[](int i)
	{
		return p[i];
	}
};
int main()
{
	std::shared_ptr<SmartPointerTest>p1(new SmartPointerTest());
	p1->MemberFuncTest();
	std::cout<<p1.use_count()<<std::endl;
	system("pause");
}

當(dāng)你這樣繼承自enable_shared_from_this的時(shí)候你就可以將自身的智能指針傳入而不是創(chuàng)建一個(gè)新的組避免了重復(fù)釋放非常的方便

關(guān)于unique_ptr我們將會在下一篇文章進(jìn)行詳細(xì)講解其實(shí)也很簡單就是他堆區(qū)資源的引用計(jì)數(shù)永遠(yuǎn)只可能是一也就是說他的資源只可能被一個(gè)指針指向附帶而來的有一些小細(xì)節(jié)和普通的shared_ptr不同我們也就留在下一章再說了

到此這篇關(guān)于C++ smart pointer全面深入講解的文章就介紹到這了,更多相關(guān)C++ smart pointer內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關(guān)文章

  • c++并查集優(yōu)化(基于size和rank)

    c++并查集優(yōu)化(基于size和rank)

    這篇文章主要介紹了c++并查集優(yōu)化(基于size和rank),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • C++容器std::vector的swap()函數(shù)使用方式

    C++容器std::vector的swap()函數(shù)使用方式

    這篇文章主要介紹了C++容器std::vector的swap()函數(shù)使用方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 詳解QT使用http通信的同步和異步

    詳解QT使用http通信的同步和異步

    在Qt與Http通信的時(shí)候,會根據(jù)不同的情況使用同步或者異步的方式進(jìn)行數(shù)據(jù)請求,下面我們就來深入了解一下http通信的同步和異步的相關(guān)知識,感興趣的小伙伴可以了解下
    2023-12-12
  • C++中based for循環(huán)的實(shí)現(xiàn)

    C++中based for循環(huán)的實(shí)現(xiàn)

    C++中的范圍for循環(huán)是一種簡潔的遍歷容器的方法,本文主要介紹了C++中based for循環(huán)的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-02-02
  • C++?多態(tài)虛函數(shù)的底層原理深入理解

    C++?多態(tài)虛函數(shù)的底層原理深入理解

    這篇文章主要介紹了C++?多態(tài)虛函數(shù)的底層原理深入理解,多態(tài)是在不同繼承關(guān)系的類對象,去調(diào)用同一函數(shù),產(chǎn)生了不同的行為,通常是父類調(diào)用子類的重寫函數(shù),在C++中就是?父類指針指向子類對象,此時(shí)父類指針的向下引用就可以實(shí)現(xiàn)多態(tài)
    2022-08-08
  • C++11互斥量的具體使用

    C++11互斥量的具體使用

    互斥量是一種同步原語,是一種線程同步的手段,用來保護(hù)多線程同時(shí)訪問的共享數(shù)據(jù),本文主要介紹了C++11互斥量的具體使用,感興趣的可以了解一下
    2023-11-11
  • C++詳細(xì)講解常用math函數(shù)的用法

    C++詳細(xì)講解常用math函數(shù)的用法

    C++提供了很多實(shí)用的數(shù)學(xué)函數(shù),如果要使用先添加頭文件,當(dāng)然,加頭文件誰都知道,接下來我們一起詳細(xì)看看各個(gè)math函數(shù)的實(shí)際使用
    2022-04-04
  • C語言實(shí)現(xiàn)影院管理系統(tǒng)

    C語言實(shí)現(xiàn)影院管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)影院管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • c++使用Easyx圖形庫實(shí)現(xiàn)飛機(jī)大戰(zhàn)

    c++使用Easyx圖形庫實(shí)現(xiàn)飛機(jī)大戰(zhàn)

    本文詳細(xì)講解了c++使用Easyx圖形庫實(shí)現(xiàn)飛機(jī)大戰(zhàn),文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12
  • QT使用SQLite數(shù)據(jù)庫超詳細(xì)教程(增刪改查、對大量數(shù)據(jù)快速存儲和更新)

    QT使用SQLite數(shù)據(jù)庫超詳細(xì)教程(增刪改查、對大量數(shù)據(jù)快速存儲和更新)

    這篇文章主要給大家介紹了關(guān)于QT使用SQLite數(shù)據(jù)庫的相關(guān)資料,其中包括增刪改查以及對大量數(shù)據(jù)快速存儲和更新,SQLite是一種嵌入式關(guān)系型數(shù)據(jù)庫管理系統(tǒng),它是一個(gè)軟件庫,提供了一個(gè)自包含、無服務(wù)器、零配置的、事務(wù)性的SQL數(shù)據(jù)庫引擎,需要的朋友可以參考下
    2024-01-01

最新評論

垣曲县| 阜南县| 图片| 大荔县| 盘锦市| 合肥市| 富源县| 当阳市| 盘锦市| 兖州市| 罗定市| 舒兰市| 河北省| 吉首市| 红桥区| 泰来县| 宜良县| 阿巴嘎旗| 中超| 甘南县| 徐水县| 固原市| 绥棱县| 英吉沙县| 公主岭市| 昭通市| 鹿邑县| 登封市| 镇远县| 百色市| 荔波县| 阳泉市| 洪洞县| 侯马市| 湖北省| 平阴县| 文水县| 乐昌市| 五大连池市| 元江| 呼图壁县|