亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

C++中的智能指針

2019-11-08 02:27:28
字體:
來源:轉載
供稿:網友

智能指針(Smart Pointer)智能在哪里

標簽(空格分隔): 學習筆記


傳統指針存在諸多的問題,比如指針所指向的對象的生命周期問題,掛起引用(dangling references),以及內存泄露(memory leaks). 如下代碼是一個傳統指針的使用過程

void Foo(){ int * ptr = new int[5]; //... //... delete[] ptr;}

以上代碼將正常運行且內存被合理釋放,但是在我們編寫較為復雜的程序時,申請了過多的東戴指針和動態內存,往往會忘了delete,或者在錯誤的時間錯誤的地點提前delete掉了指針,這無疑是會導致程序崩潰或者內存泄露的。 智能指針是RAII(Resource Acquisition is initialization)用來動態的分配內存。它提供了普通指針的所有接口外加少數異常處理。在構造階段,它將分配內存,而在非其作用域內將自動釋放所占有的內存。 在C++98中,使用 auto_ptr來解決上述問題。

1. auto_ptr

auto_ptr在所指對象作用域結束之后會自動調用其析構函數,這樣就不用手動的delete,看如下代碼:

#include <iostream>#include <memory>using namespace std;class autoPtrTest{public: //constructor function autoPtrTest(int a = 0) :m_a(a){} //deconstructor function ~autoPtrTest() { cout << "calling deconstructor" << endl; getchar(); }public: int m_a;};int main(){ //create an auto_ptr(p) to point a autoPtrTest class, and initialize with 5 auto_ptr<autoPtrTest> p(new autoPtrTest(5)); cout << p->m_a << endl; return 0;}

運行結果如下圖所示: 捕獲.PNG-31.3kB 當類型為auto_ptr的指針p指向的對象作用域結束后,自動調用了該類的析構函數. 但是,使用auto_ptr時,無可避免的會出現以下幾個問題,這是由auto_ptr自身的性質決定的 1)auto_ptr會傳遞它本身的ownership,當其被賦值給另一個auto_ptr對象。正如下述程序所示,一個auto_ptr對象傳遞給函數Fun()中的auto_ptr對象時,其ownership,或者說是smartness將不再返回給原auto_ptr所指向的p。

#include <iostream>#include <memory>using namespace std;class autoPtrTest{public: //constructor function autoPtrTest(int a = 0) :m_a(a){} //deconstructor function ~autoPtrTest() { cout << "calling deconstructor" << endl; }public: int m_a;};void Fun(auto_ptr<autoPtrTest> p1){ cout << p1->m_a << endl; cout << "Fun()end" << endl;}int main(){ auto_ptr<autoPtrTest> p(new autoPtrTest(5)); Fun(p); cout << p->m_a << endl; return 0;}

程序運行結果如下圖所示: 捕獲.PNG-42.8kB 這是因為在調用函數Fun時,main中創建的指針p在函數中將自己的所有權給了p1,所以離開p1的作用域時,編譯器自動調用了析構函數,此時main中p為一個空指的野指針,所以程序報錯。 2)auto_ptr不能使用于數組對象。 這里的意思是不能使用于操作符new[] 3)auto_ptr不能使用于一些標準的容器庫。比如vector,list,map等等 C++11提出了新型的智能指針,并且都賦予了其相應的意圖。

2.shared_ptr

shared_ptr設計的目的很簡單:多個共享指針可以指向同一個對象,而當最后一個共享指針在作用域范圍內結束時,內存才會被自動的釋放。

int main(){ // share_ptr 常規的創建過程 shared_ptr<int> sptr1(new int); // 使用make_shared 來加速創建過程 // shared_ptr 自動分配內存,并且保證引用計數 // 而make_shared則是按照這種方法來初始化 shared_ptr<int> sptr2 = make_shared<int>(100); // 可以通過use_count() 來查看引用計數 cout << "sptr2 referenced count: " << sptr2.use_count() << endl; shared_ptr<int> sptr3 = sptr2; cout << "sptr2 referenced count: " << sptr2.use_count() << endl; cout << "*sptr2 = " << *sptr2 << endl; getchar(); return 0;}

上述代碼的運行結果為: 捕獲.PNG-12.7kB 上述代碼創建了一個shared_ptr指針指向了一個裝著整型值且值為100的內存塊,并且引用計數為1,。當其他共享指針通過sptr1來創建時,引用計數將為2。

#include <iostream>#include <memory>using namespace std;class Test {public: Test(int a = 0) : m_a(a) {} ~Test() { cout << "Calling destructor" << endl; }public: int m_a;};int main(){ // 如果用以下形式,則只會調用delete,則不會調用 // delete[ ]; 此時只會調用一次析構函數 shared_ptr<Test> sptr1(new Test[5]); // 采用以下形式,lambda表達式,顯示調用 // delete[] 來刪除所有的對象。 shared_ptr<Test> sptr2(new Test[5], [](Test* p) {delete[] p;}); return 0;}

用戶可以顯式的調用函數,lambda表達式,函數對象來調用對于shared_ptr為數組對象的析構函數delete[]。 同時,shared_ptr為用戶提供了以下方便接口: shared_ptr提供解引用*, 以及->來普通指針的相關操作。同時,還提供了以下的接口: get(): To get the resource associated with the shared_ptr. reset(): To yield the ownership of the associated memory block. If this is the last shared_ptrowning the resource, then the resource is released automatically. unique: To know whether the resource is managed by only this shared_ptr instance. Operator bool: To check whether the shared_ptr owns a memory block or not. Can be used with an if condition. 但是,shared_ptr同樣也存在問題: 1)當一個內存塊與shared_ptr綁定相關,并且屬于不同組時,將會發生錯誤。所有的shared_ptr共享一個組的同一個共享引用。

int main(){ shared_ptr<int> sptr1(new int); shared_ptr<int> sptr2 = sptr1; shared_otr<int> sptr3; sptr3 = sptr2; return 0;}

以下表格給出了相應的引用計數:

pointer count
shared_ptrstPR1(new int) 1
shared_ptr sptr2 = sptr1 2
sptr3 = sptr2 3
when main ends->sptr3 goes out of scope 2
sptr2 goes out of scope 1
sptr1 goes out of scope 0->the resources is released

以上代碼運行正常,然而當運行以下代碼是:

int main(){ int *p = new int; shared_ptr<int>sptr1(p); shared_ptr<int>sptr2(p); return 0;}
pointer count
shared_ptrsptr1(p) 1
shared_ptrsptr2(p) 1
when main ends->sptr1 goes out of scope 0 p is destroyed
sptr2->goes out of scope 0 and crash

為了避免這種情況發生,最好不用從裸指針中建立共享指針。 2)問題2:另一個問題是,正如上述問題,如果從一個裸指針中創建一個共享指針,只有一個共享指針時,可以正常運行,但是當裸指針被釋放時,共享指針也會crash。 3)循環引用時,如果資源被非恰當釋放,也會出現問題。

#include <iostream>#include <memory>using namespace std;class B;class A{public: A() : m_sptrB(nullptr) {} ; ~A() { cout << "A is destroyed" << endl; } shared_ptr<B> m_sptrB;};class B{public: B() : m_sptrA(nullptr) {}; ~B() { cout << "B is destroyed" << endl; } shared_ptr<A> m_sptrA;};int main(){ shared_ptr<B> sptrB(new B); shared_ptr<A> sptrA(new A); sptrB->m_sptrA = sptrA; sptrA->m_sptrB = sptrB; return 0;}

當類A包含了指向B的共享指針,而類B包含了指向A 的恭喜那個指針時,sptrA和SptrB相關的資源都將不會被釋放。結果如下圖:

pointer count
shared_ptr sptrB(new B) 1
shared_ptr sptrA(new A) 1
sptrB->m_sptrA = sptrA sptrA->2
sptrA->m_sptrB = sptrB sptrB->2
main ends->sptrA goes out of scope sptrA->1
main ends->sptrB gos out of scope sptrB->1

3. weak_ptr

一個弱指針,提供的是一種共享語義定義而不是擁有語義定義。這就意味著一個弱指針可以通過shared_ptr共享資源。所以要創建弱指針,必須是已經擁有資源但是是一個共享指針。

一個弱指針并不允許諸如普通指針所提供的*和->。因為他并不是資源的擁有者。

那么如何利用弱指針呢? **weak_ptr只能用于跟蹤一個共享的資源,但并不實際擁有,也不會阻礙資源的釋放。讀取共享資源前需要先執行lock,得到shared_ptr后才能進行訪問。 當兩個對象需要互相引用時,我們總希望其中一個對象擁有另一個對象的強引用,而另一個對象擁有自己的弱引用,如果兩個對象都是強引用,則容易引起循環引用,導致兩個對象都無法正確釋放。**

用weak_ptr作為一個類似share_ptr但卻能懸浮的指針 有一個矛盾,一個靈巧指針可以像shared_ptr 一樣方便,但又不參與管理被指對象的所有權。換句話說,需要一個像shared_ptr但又不影響對象引用計數的指針。這類指針會有一個shared_ptr沒有的問題:被指的對象有可能已經被銷毀。一個良好的靈巧指針應該能處理這種情況,通過跟蹤什么時候指針會懸浮,比如在被指對象不復存在的時候。這正是weak_ptr這類型靈巧指針所能做到的。

weak_ptr一般是通過shared_ptr來構造的。當使用shared_ptr來初始化weak_ptr時,weak_ptr就指向了相同的地方,但是不改變所指對象的引用計數。 20150723144259417-22.3kB 從上圖可以看書,通過將一個weak_ptr賦值給另一個時會增加其弱引用計數。

如果弱引用指針所指向的資源,被其共享指針所釋放時,這時候弱指針將會過期。如何檢測一個弱指針是否指向一個合法的資源呢?有以下兩種途徑。

調用use_count()來得到引用計數。注意這里返回的是強引用計數。 調用expired()函數,這比調用use_count要快的多。 同時,我們可以通過對一個weak_ptr調用函數lock()來得到一個shared_ptr?;蛘咧苯訉σ粋€weak_ptr進行強制轉換。

int main(){ shared_ptr<A> sptr<new A> weak_ptr<A> wptr(sptr); shared_ptr<A> sptr2 = wptr.lock(); shared_ptr<B> sptrB(new B); shared_ptr<A> sptrA(new A); sptrB->m_sptrA = sptrA; sptrA->m_sptrB = sptrB; return 0;}

以上方法將增加強引用計數 以下例子將展示如何使用weak_ptr解決循環引用問題

#include <iostream>#include <memory>using namespace std;class B;class A{public: A() : m_a(5) {} ; ~A() { cout << "A is destroyed" << endl; } void PrintSpB() ; weak_ptr<B> m_sptrB; int m_a;};class B {public: B() : m_b(10) {} ; ~B() { cout << "B is destroyed" << endl; } weak_ptr<A> m_sptrA; int m_b;};void A::PrintSpB(){ if( !m_sptrB.expired() ) cout << m_sptrB.lock()->m_b << endl;}int main(){ shared_ptr<B> sptrB(new B); shared_ptr<A> sptrA(new A); sptrB->m_sptrA = sptrA; sptrA->m_sptrB = sptrB; sptrA->PrintSpB(); return 0;}

4.unique_ptr

unique_ptr幾乎是易出錯的auto_ptr的另一種形式。unique_ptr遵循專用所有權語義。在任何時刻,資源只被唯一的一個unique_ptr所占有。當auto_ptr不在作用域范圍內時,資源就會被釋放。當一個資源被其他資源重寫時,如果先前的資源已經被釋放,這保證了相關的資源也會被釋放。 creation(創建) unique_ptr創建的過程和shared_ptr創建的過程大同小異,所不同的是創建的數組形式的對象。 unique_ptr提供了專用創建數組對象的析構調用delete[]而不是delete當其不在作用域范圍內。

unique_ptr<int[]>unptr(new int[5]);

對于資源的擁有權(ownership)可以從一個unique_ptr通過另一個進行賦值來傳遞。

需要記住的是:unique_ptr并不提供復制機制copy semantics(包括復制賦值copy assignment以及復制構造函數copy construction)而是一種移動機制。

Interface(接口)

unique_ptr提供的接口與普通常規指針的接口非常相似,但是并不提供指針運算。 unique_ptr提供release()函數來進行yield the ownership。release()和reset()函數的區別在于,reset()會對資源進行銷毀。

參考文獻:


上一篇:c++學習筆記

下一篇:C++中的常量函數

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美精品免费在线| 91精品国产成人| 亚洲精品久久久久久久久久久| 欧美午夜宅男影院在线观看| 欧美日韩另类在线| 精品国产乱码久久久久酒店| 国产精品av免费在线观看| 91精品国产91久久久久久最新| 成人免费淫片视频软件| 国产精品日日做人人爱| 欧美国产精品日韩| 久久久久久国产精品三级玉女聊斋| 久久国内精品一国内精品| 国产亚洲精品高潮| 色青青草原桃花久久综合| 日韩欧美a级成人黄色| 亚洲社区在线观看| 欧美黑人巨大xxx极品| 久久综合88中文色鬼| 日韩欧美在线免费| 国产精品精品视频一区二区三区| 成人网在线免费看| 色樱桃影院亚洲精品影院| 亚洲精品一区av在线播放| 精品亚洲精品福利线在观看| 亚洲欧美变态国产另类| 大量国产精品视频| 美女黄色丝袜一区| 成人春色激情网| 国产日韩在线亚洲字幕中文| 日韩高清免费观看| 91chinesevideo永久地址| 日韩欧美高清在线视频| 亚洲人精品午夜在线观看| 国产婷婷成人久久av免费高清| 国产福利视频一区二区| 国模精品视频一区二区| 国产日韩中文在线| 亚洲成人黄色网| 国产99久久久欧美黑人| 日本久久久a级免费| 精品国产成人av| 欧美成年人网站| 精品国偷自产在线| 国产亚洲欧洲在线| 久久全国免费视频| 久久精品国产99国产精品澳门| 92国产精品久久久久首页| 国产欧美一区二区三区久久| 国产一区二区在线免费视频| 欧美日韩在线免费观看| 国产日韩av在线播放| 91九色单男在线观看| 日韩在线观看免费网站| 日韩av免费在线播放| 国产精品黄色影片导航在线观看| 欧美日韩国产123| 日韩av在线免费看| 影音先锋欧美精品| 成人国产在线激情| 91中文字幕在线| 欧美激情精品久久久久久| 欧美在线影院在线视频| 久久精品福利视频| 欧美性猛交xxxx偷拍洗澡| 日韩网站在线观看| 中文字幕日韩欧美在线视频| 国产+成+人+亚洲欧洲| 91精品国产91久久久久久| 伊人久久久久久久久久久久久| 欧美日韩中文字幕综合视频| 国产999精品久久久影片官网| 久久精品福利视频| 国产欧美韩国高清| 久久在线免费视频| 91色精品视频在线| 国内精品中文字幕| 91免费看片网站| 久久视频在线播放| 国产精品免费久久久久影院| 97在线观看视频| 国产一区欧美二区三区| 久久久之久亚州精品露出| 伊人成人开心激情综合网| 欧美在线精品免播放器视频| 色综久久综合桃花网| 国产欧美在线看| 亚洲国产精品va在线看黑人| 欧美三级欧美成人高清www| 日韩精品www| 亚洲精品videossex少妇| 亚洲品质视频自拍网| 少妇高潮久久久久久潘金莲| 超碰日本道色综合久久综合| 久久久久久久久久国产精品| 日韩电影免费在线观看中文字幕| 久久成人免费视频| 日韩在线视频免费观看| 久久精品国产欧美亚洲人人爽| 欧美日韩免费看| 久久免费精品视频| 欧美日韩国产va另类| 欧美日韩亚洲精品一区二区三区| 久久久av电影| 亚洲free性xxxx护士hd| 亚洲欧美激情视频| 91av在线视频观看| 欧日韩在线观看| 久久99国产精品自在自在app| 欧美电影在线观看| 97香蕉久久超级碰碰高清版| 亚洲欧美国产精品久久久久久久| 国产自产女人91一区在线观看| 亚洲精品中文字幕有码专区| 在线观看国产欧美| 亚洲国产成人久久综合一区| 成人欧美一区二区三区黑人| 97精品视频在线| 国产精品一区二区久久国产| 欧美黄色www| 成人黄色午夜影院| 2020欧美日韩在线视频| 久久人人爽人人爽人人片亚洲| 久久91精品国产91久久跳| 成人午夜激情免费视频| 日日摸夜夜添一区| 久久国产精品网站| 97视频在线观看播放| 国语自产精品视频在免费| 欧美激情第6页| 在线看日韩欧美| 91亚洲国产成人精品性色| 亚洲精品日韩丝袜精品| 国产剧情久久久久久| 国产性猛交xxxx免费看久久| 亚洲成人黄色在线| 欧美成人精品一区二区| 欧美性xxxx极品hd满灌| 一本一本久久a久久精品综合小说| 亚洲国产成人精品电影| 亚洲新声在线观看| 色噜噜亚洲精品中文字幕| 欧美大尺度激情区在线播放| 国产午夜精品免费一区二区三区| 欧美性猛交丰臀xxxxx网站| 日本精品性网站在线观看| 中文字幕亚洲无线码在线一区| 92国产精品久久久久首页| 91啪国产在线| 日韩欧美在线国产| 欧美黄色片视频| 久久久免费高清电视剧观看| 色多多国产成人永久免费网站| 日韩亚洲欧美中文高清在线| 国产婷婷成人久久av免费高清| 久久777国产线看观看精品| 国产高清视频一区三区| 亚洲美女av网站| 欧美日韩国产成人在线| 浅井舞香一区二区| 国产精品一区久久| 成人免费看片视频| 免费不卡欧美自拍视频| 亚洲自拍中文字幕|