日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

【Smart_Point】C/C++ 中共享指针 shared_ptr

發(fā)布時間:2023/11/27 生活经验 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Smart_Point】C/C++ 中共享指针 shared_ptr 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. 共享指針 shared_ptr

目錄

1. 共享指針 shared_ptr

1.1 共享指針解決的問題?

1.2 創(chuàng)建 shared_ptr 對象

1.3 分離關(guān)聯(lián)的原始指針

1.4 自定義刪除器 Deleter

1.5 shared_ptr 相對于普通指針的優(yōu)缺點

1.6 創(chuàng)建 shared_ptr 時注意事項


1.1 共享指針解決的問題?

shared_ptr 是C++11提供的一種智能指針類( 智能指針是一個可以像指針一樣工作的對象,但是當它不再被使用時,可以自動刪除動態(tài)分配的內(nèi)存)。它足夠智能,可以在任何地方都不使用時自動刪除相關(guān)指針,從而幫助徹底消除內(nèi)存泄漏( 也就是說,即使已經(jīng)不再需要內(nèi)存了,但指針仍然未被刪除。另外還有雙重刪除的問題,當程序的某部分要刪除一個已經(jīng)被刪除的指針時,即可出現(xiàn)這種情況。如果被刪除的內(nèi)存已經(jīng)進行了重新分配,則雙重刪除會對程序造成破壞。)和懸空指針( 指針已經(jīng)被刪除了,但其內(nèi)存仍然在使用中 )的問題。 它遵循共享所有權(quán)的概念,即不同的 shared_ptr 對象可以與相同的指針相關(guān)聯(lián),并在內(nèi)部使用引用計數(shù)機制來實現(xiàn)這一點。 每個 shared_ptr 對象在內(nèi)部指向兩個內(nèi)存位置: 1、指向?qū)ο蟮闹羔槨?2、用于控制引用計數(shù)數(shù)據(jù)的指針。 共享所有權(quán)如何在參考計數(shù)的幫助下工作: 1、當新的 shared_ptr 對象與指針關(guān)聯(lián)時,則在其構(gòu)造函數(shù)中,將與此指針關(guān)聯(lián)的引用計數(shù)增加1。 2、當任何 shared_ptr 對象超出作用域時,則在其析構(gòu)函數(shù)中,它將關(guān)聯(lián)指針的引用計數(shù)減1。如果引用計數(shù)變?yōu)?,則表示沒有其他 ~對象與此內(nèi)存關(guān)聯(lián),在這種情況下,它使用delete函數(shù)刪除該內(nèi)存。

1.2 創(chuàng)建 shared_ptr 對象

1.2.1 使用原始指針創(chuàng)建 shared_ptr 對象

std::shared_ptr<int> p1(new int());

上面這行代碼在堆上創(chuàng)建了兩塊內(nèi)存:

1:存儲int

2:用于引用計數(shù)的內(nèi)存,管理附加此內(nèi)存的 shared_ptr 對象的計數(shù),最初計數(shù)將為1。

檢查 shared_ptr 對象的引用計數(shù)

p1.use_count();

創(chuàng)建空的 shared_ptr 對象

因為帶有參數(shù)的 shared_ptr 構(gòu)造函數(shù)是 explicit 類型的,所以不能像這樣std::shared_ptr<int> p1 = new int();隱式調(diào)用它構(gòu)造函數(shù)。創(chuàng)建新的shared_ptr對象的最佳方法是使用std :: make_shared:

std::shared_ptr<int> p1 = std::make_shared<int>();

std::make_shared 一次性為int對象和用于引用計數(shù)的數(shù)據(jù)都分配了內(nèi)存,而new操作符只是為int分配了內(nèi)存。

1.3 分離關(guān)聯(lián)的原始指針

要使 shared_ptr 對象取消與相關(guān)指針的關(guān)聯(lián),可以使用reset()函數(shù): 不帶參數(shù)的reset():

p1.reset();

它將引用計數(shù)減少1,如果引用計數(shù)變?yōu)?,則刪除指針。 帶參數(shù)的reset():

p1.reset(new int(34));

在這種情況下,它將在內(nèi)部指向新指針,因此其引用計數(shù)將再次變?yōu)?。 使用nullptr重置

p1 = nullptr; 

shared_ptr是一個偽指針,本質(zhì)類

shared_ptr充當普通指針,我們可以將*->shared_ptr 對象一起使用,也可以像其他 shared_ptr 對象一樣進行比較;

1.3.2 完整示例

#include <iostream>
#include  <memory> // 需要包含這個頭文件
?
int main()
{// 使用 make_shared 創(chuàng)建空對象std::shared_ptr<int> p1 = std::make_shared<int>();*p1 = 78;std::cout << "p1 = " << *p1 << std::endl; // 輸出78
?// 打印引用個數(shù):1std::cout << "p1 Reference count = " << p1.use_count() << std::endl;
?// 第2個 shared_ptr 對象指向同一個指針std::shared_ptr<int> p2(p1);
?// 下面兩個輸出都是:2std::cout << "p2 Reference count = " << p2.use_count() << std::endl;std::cout << "p1 Reference count = " << p1.use_count() << std::endl;
?// 比較智能指針,p1 等于 p2if (p1 == p2) {std::cout << "p1 and p2 are pointing to same pointer\n";}
?std::cout<<"Reset p1 "<<std::endl;
?// 無參數(shù)調(diào)用reset,無關(guān)聯(lián)指針,引用個數(shù)為0p1.reset();std::cout << "p1 Reference Count = " << p1.use_count() << std::endl;// 帶參數(shù)調(diào)用reset,引用個數(shù)為1p1.reset(new int(11));std::cout << "p1  Reference Count = " << p1.use_count() << std::endl;
?// 把對象重置為NULL,引用計數(shù)為0p1 = nullptr;std::cout << "p1  Reference Count = " << p1.use_count() << std::endl;if (!p1) {std::cout << "p1 is NULL" << std::endl; // 輸出}return 0;
}

輸出結(jié)果

p1 = 78
p1 Reference count = 1
p2 Reference count = 2
p1 Reference count = 2
p1 and p2 are pointing to same pointer
Reset p1 
p1 Reference Count = 0
p1  Reference Count = 1
p1  Reference Count = 0
p1 is NULL

1.4 自定義刪除器 Deleter

1.4.1 下面將討論如何將自定義刪除器與 std :: shared_ptr 一起使用。

shared_ptr 對象超出范圍時,將調(diào)用其析構(gòu)函數(shù)。在其析構(gòu)函數(shù)中,它將引用計數(shù)減1,如果引用計數(shù)的新值為0,則刪除關(guān)聯(lián)的原始指針。 析構(gòu)函數(shù)中刪除內(nèi)部原始指針,默認調(diào)用的是delete()函數(shù)。

delete Pointer;

有些時候在析構(gòu)函數(shù)中,delete函數(shù)并不能滿足我們的需求,可能還想加其他的處理。

shared_ptr 對象指向數(shù)組

std::shared_ptr<int> p3(new int[12]);
像這樣申請的數(shù)組,應(yīng)該調(diào)用delete []釋放內(nèi)存,而shared_ptr析構(gòu)函數(shù)中默認delete并不能滿足需求。

shared_ptr添加自定義刪除器

在上面在這種情況下,我們可以將回調(diào)函數(shù)傳遞給 shared_ptr 的構(gòu)造函數(shù),該構(gòu)造函數(shù)將從其析構(gòu)函數(shù)中調(diào)用以進行刪除,即

// 自定義刪除器
void deleter(Sample * x)
{std::cout << "DELETER FUNCTION CALLED\n";delete[] x;
}
// 構(gòu)造函數(shù)傳遞自定義刪除器指針
std::shared_ptr<Sample> p3(new Sample[12], deleter);

完整的示例:

#include <iostream>
#include <memory>struct Sample
{Sample() {std::cout << "Sample\n";}~Sample() {std::cout << "~Sample\n";}
};void deleter(Sample * x)
{std::cout << "Custom Deleter\n";delete[] x;
}int main()
{std::shared_ptr<Sample> p3(new Sample[2], deleter);return 0;
}

輸出結(jié)果:

Sample
Sample
Custom Deleter
~Sample
~Sample

1.4.2 使用Lambda 表達式 / 函數(shù)對象作為刪除器

class Deleter
{public:void operator() (Sample * x) {std::cout<<"DELETER FUNCTION CALLED\n";delete[] x;}
};// 函數(shù)對象作為刪除器
std::shared_ptr<Sample> p3(new Sample[3], Deleter());// Lambda表達式作為刪除器,無需依賴/調(diào)用實現(xiàn)class Deleter類
std::shared_ptr<Sample> p4(new Sample[3], [](Sample * x){std::cout<<"DELETER FUNCTION CALLED\n";delete[] x;
});

1.5 shared_ptr 相對于普通指針的優(yōu)缺點

缺少 ++, – – 和 [] 運算符

與普通指針相比,shared_ptr僅提供->*==運算符,沒有+-++--[]等運算符。 示例:

#include<iostream>
#include<memory>struct Sample {void dummyFunction() {std::cout << "dummyFunction" << std::endl;}
};int main()
{std::shared_ptr<Sample> ptr = std::make_shared<Sample>();(*ptr).dummyFunction(); // 正常ptr->dummyFunction(); // 正常// ptr[0]->dummyFunction(); // 錯誤方式// ptr++;  // 錯誤方式//ptr--;  // 錯誤方式std::shared_ptr<Sample> ptr2(ptr);if (ptr == ptr2) // 正常std::cout << "ptr and ptr2 are equal" << std::endl;return 0;
}

NULL檢測

當我們創(chuàng)建 shared_ptr 對象而不分配任何值時,它就是空的普通指針不分配空間的時候相當于一個野指針指向垃圾空間,且無法判斷指向的是否是有用數(shù)據(jù)**shared_ptr 檢測空值方法**

std::shared_ptr<Sample> ptr3;
if(!ptr3)std::cout<<"Yes, ptr3 is empty" << std::endl;
if(ptr3 == NULL)std::cout<<"ptr3 is empty" << std::endl;
if(ptr3 == nullptr)std::cout<<"ptr3 is empty" << std::endl;

1.6 創(chuàng)建 shared_ptr 時注意事項

1.6.1 不要使用同一個原始指針構(gòu)造 shared_ptr

創(chuàng)建多個 shared_ptr 的正常方法是使用一個已存在的shared_ptr 進行創(chuàng)建,而不是使用同一個原始指針進行創(chuàng)建。 示例:

    int *num = new int(23);std::shared_ptr<int> p1(num);std::shared_ptr<int> p2(p1);  // 正確使用方法std::shared_ptr<int> p3(num); // 不推薦std::cout << "p1 Reference = " << p1.use_count() << std::endl; // 輸出 2std::cout << "p2 Reference = " << p2.use_count() << std::endl; // 輸出 2std::cout << "p3 Reference = " << p3.use_count() << std::endl; // 輸出 1

假如使用原始指針num創(chuàng)建了p1,又同樣方法創(chuàng)建了p3p1超出作用域時會調(diào)用delete釋放num內(nèi)存,此時num成了懸空指針,當p3超出作用域再次delete的時候就可能會出錯。

1.6.2 不要用棧中的指針構(gòu)造 shared_ptr 對象

shared_ptr 默認的構(gòu)造函數(shù)中使用的是delete來刪除關(guān)聯(lián)的指針,所以構(gòu)造的時候也必須使用new出來的堆空間的指針。 示例:

#include<iostream>
#include<memory>int main()
{int x = 12;std::shared_ptr<int> ptr(&x);return 0;
}

shared_ptr 對象超出作用域調(diào)用析構(gòu)函數(shù)delete 指針&x時會出錯。

1.6.3 建議使用 make_shared

為了避免以上兩種情形,建議使用make_shared()<>創(chuàng)建 shared_ptr 對象,而不是使用默認構(gòu)造函數(shù)創(chuàng)建。

std::shared_ptr<int> ptr_1 = make_shared<int>();
std::shared_ptr<int> ptr_2 (ptr_1);

另外不建議使用get()函數(shù)獲取 shared_ptr 關(guān)聯(lián)的原始指針,因為如果在 shared_ptr 析構(gòu)之前手動調(diào)用了delete函數(shù),同樣會導致類似的錯誤。

總結(jié)

以上是生活随笔為你收集整理的【Smart_Point】C/C++ 中共享指针 shared_ptr的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。