久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

【轉(zhuǎn)】C++ 智能指針詳解

 techres 2011-08-04

C++ 智能指針詳解

 

一、簡(jiǎn)介

由于 C++ 語(yǔ)言沒(méi)有自動(dòng)內(nèi)存回收機(jī)制,,程序員每次 new 出來(lái)的內(nèi)存都要手動(dòng) delete,。程序員忘記 delete,,流程太復(fù)雜,最終導(dǎo)致沒(méi)有 delete,,異常導(dǎo)致程序過(guò)早退出,,沒(méi)有執(zhí)行 delete 的情況并不罕見。

用智能指針便可以有效緩解這類問(wèn)題,,本文主要講解參見的智能指針的用法,。包括:std::auto_ptrboost::scoped_ptr,、boost::shared_ptr,、boost::scoped_arrayboost::shared_array,、boost::weak_ptr,、boost:: intrusive_ptr你可能會(huì)想,,如此多的智能指針就為了解決new,、delete匹配問(wèn)題,真的有必要嗎,?看完這篇文章后,,我想你心里自然會(huì)有答案。

    下面就按照順序講解如上 7 種智能指針(smart_ptr),。

 

二、具體使用

1,、總括

對(duì)于編譯器來(lái)說(shuō),,智能指針實(shí)際上是一個(gè)棧對(duì)象,并非指針類型,,在棧對(duì)象生命期即將結(jié)束時(shí),,智能指針通過(guò)析構(gòu)函數(shù)釋放有它管理的堆內(nèi)存。所有智能指針都重載了“operator->”操作符,,直接返回對(duì)象的引用,,用以操作對(duì)象。訪問(wèn)智能指針原來(lái)的方法則使用“.”操作符,。

訪問(wèn)智能指針包含的裸指針則可以用 get() 函數(shù),。由于智能指針是一個(gè)對(duì)象,所以if (my_smart_object)永遠(yuǎn)為真,,要判斷智能指針的裸指針是否為空,,需要這樣判斷:if (my_smart_object.get())

智能指針包含了 reset() 方法,,如果不傳遞參數(shù)(或者傳遞 NULL),,則智能指針會(huì)釋放當(dāng)前管理的內(nèi)存,。如果傳遞一個(gè)對(duì)象,則智能指針會(huì)釋放當(dāng)前對(duì)象,,來(lái)管理新傳入的對(duì)象,。

我們編寫一個(gè)測(cè)試類來(lái)輔助分析:

class Simple {

 public:

  Simple(int param = 0) {

    number = param;

    std::cout << "Simple: " << number << std::endl; 

  }

 

  ~Simple() {

    std::cout << "~Simple: " << number << std::endl;

  }

 

  void PrintSomething() {

    std::cout << "PrintSomething: " << info_extend.c_str() << std::endl;

  }

 

  std::string info_extend;

  int number;

};

 

2std::auto_ptr

std::auto_ptr 屬于 STL,,當(dāng)然在 namespace std 中,,包含頭文件 #include<memory> 便可以使用。std::auto_ptr 能夠方便的管理單個(gè)堆內(nèi)存對(duì)象,。

我們從代碼開始分析:

void TestAutoPtr() {

std::auto_ptr<Simple> my_memory(new Simple(1));   // 創(chuàng)建對(duì)象,,輸出:Simple1

if (my_memory.get()) {                            // 判斷智能指針是否為空

my_memory->PrintSomething();                    // 使用 operator-> 調(diào)用智能指針對(duì)象中的函數(shù)

my_memory.get()->info_extend = "Addition";      // 使用 get() 返回裸指針,然后給內(nèi)部對(duì)象賦值

my_memory->PrintSomething();                    // 再次打印,,表明上述賦值成功

(*my_memory).info_extend += " other";           // 使用 operator* 返回智能指針內(nèi)部對(duì)象,,然后用“.”調(diào)用智能指針對(duì)象中的函數(shù)

my_memory->PrintSomething();                    // 再次打印,表明上述賦值成功

  }

}                                                   // my_memory 棧對(duì)象即將結(jié)束生命期,,析構(gòu)堆對(duì)象 Simple(1)

執(zhí)行結(jié)果為:

Simple: 1

PrintSomething:

PrintSomething: Addition

PrintSomething: Addition other

~Simple: 1

上述為正常使用 std::auto_ptr 的代碼,,一切似乎都良好,無(wú)論如何不用我們顯示使用該死的 delete 了,。

 

其實(shí)好景不長(zhǎng),,我們看看如下的另一個(gè)例子:

void TestAutoPtr2() {

  std::auto_ptr<Simple> my_memory(new Simple(1));

  if (my_memory.get()) {

    std::auto_ptr<Simple> my_memory2;   // 創(chuàng)建一個(gè)新的 my_memory2 對(duì)象

    my_memory2 = my_memory;             // 復(fù)制舊的 my_memory my_memory2

    my_memory2->PrintSomething();       // 輸出信息,復(fù)制成功

    my_memory->PrintSomething();        // 崩潰

  }

}

最終如上代碼導(dǎo)致崩潰,,如上代碼時(shí)絕對(duì)符合 C++ 編程思想的,,居然崩潰了,跟進(jìn) std::auto_ptr 的源碼后,,我們看到,,罪魁禍?zhǔn)资?#8220;my_memory2 = my_memory”,這行代碼,,my_memory2 完全奪取了 my_memory 的內(nèi)存管理所有權(quán),,導(dǎo)致 my_memory 懸空,最后使用時(shí)導(dǎo)致崩潰,。

所以,,使用 std::auto_ptr 時(shí),絕對(duì)不能使用“operator=”操作符,。作為一個(gè)庫(kù),,不允許用戶使用,確沒(méi)有明確拒絕[1],,多少會(huì)覺得有點(diǎn)出乎預(yù)料,。

 

看完 std::auto_ptr 好景不長(zhǎng)的第一個(gè)例子后,讓我們?cè)賮?lái)看一個(gè):

void TestAutoPtr3() {

  std::auto_ptr<Simple> my_memory(new Simple(1));

 

  if (my_memory.get()) {

    my_memory.release();

  }

}

執(zhí)行結(jié)果為:

Simple: 1

看到什么異常了嗎,?我們創(chuàng)建出來(lái)的對(duì)象沒(méi)有被析構(gòu),,沒(méi)有輸出“~Simple: 1,,導(dǎo)致內(nèi)存泄露當(dāng)我們不想讓 my_memory 繼續(xù)生存下去,,我們調(diào)用 release() 函數(shù)釋放內(nèi)存,,結(jié)果卻導(dǎo)致內(nèi)存泄露(在內(nèi)存受限系統(tǒng)中,如果my_memory占用太多內(nèi)存,,我們會(huì)考慮在使用完成后,,立刻歸還,而不是等到 my_memory 結(jié)束生命期后才歸還),。

正確的代碼應(yīng)該為:

void TestAutoPtr3() {

  std::auto_ptr<Simple> my_memory(new Simple(1));

  if (my_memory.get()) {

    Simple* temp_memory = my_memory.release();

    delete temp_memory;

  }

}

void TestAutoPtr3() {

  std::auto_ptr<Simple> my_memory(new Simple(1));

  if (my_memory.get()) {

    my_memory.reset();  // 釋放 my_memory 內(nèi)部管理的內(nèi)存

  }

}

原來(lái) std::auto_ptr release() 函數(shù)只是讓出內(nèi)存所有權(quán),,這顯然也不符合 C++ 編程思想。

總結(jié):std::auto_ptr 可用來(lái)管理單個(gè)對(duì)象的對(duì)內(nèi)存,,但是,,請(qǐng)注意如下幾點(diǎn):

(1)    盡量不要使用“operator=”。如果使用了,,請(qǐng)不要再使用先前對(duì)象,。

(2)    記住 release() 函數(shù)不會(huì)釋放對(duì)象,僅僅歸還所有權(quán),。

(3)    std::auto_ptr 最好不要當(dāng)成參數(shù)傳遞(讀者可以自行寫代碼確定為什么不能),。

(4)    由于 std::auto_ptr 的“operator=”問(wèn)題,有其管理的對(duì)象不能放入 std::vector 等容器中,。

(5)    ……

使用一個(gè) std::auto_ptr 的限制還真多,,還不能用來(lái)管理堆內(nèi)存數(shù)組,這應(yīng)該是你目前在想的事情吧,,我也覺得限制挺多的,,哪天一個(gè)不小心,就導(dǎo)致問(wèn)題了,。

由于 std::auto_ptr 引發(fā)了諸多問(wèn)題,一些設(shè)計(jì)并不是非常符合 C++ 編程思想,,所以引發(fā)了下面 boost 的智能指針,,boost 智能指針可以解決如上問(wèn)題。

讓我們繼續(xù)向下看,。

 

3,、boost::scoped_ptr

boost::scoped_ptr 屬于 boost 庫(kù),定義在 namespace boost 中,,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用,。boost::scoped_ptr std::auto_ptr 一樣,可以方便的管理單個(gè)堆內(nèi)存對(duì)象,,特別的是,,boost::scoped_ptr 獨(dú)享所有權(quán),,避免了 std::auto_ptr 惱人的幾個(gè)問(wèn)題。

我們還是從代碼開始分析:

void TestScopedPtr() {

  boost::scoped_ptr<Simple> my_memory(new Simple(1));

  if (my_memory.get()) {

    my_memory->PrintSomething();

    my_memory.get()->info_extend = "Addition";

    my_memory->PrintSomething();

    (*my_memory).info_extend += " other";

    my_memory->PrintSomething();

   

    my_memory.release();           // 編譯 error: scoped_ptr 沒(méi)有 release 函數(shù)

    std::auto_ptr<Simple> my_memory2;

    my_memory2 = my_memory;        // 編譯 error: scoped_ptr 沒(méi)有重載 operator=,,不會(huì)導(dǎo)致所有權(quán)轉(zhuǎn)移

  }

}

首先,,我們可以看到,boost::scoped_ptr 也可以像 auto_ptr 一樣正常使用,。但其沒(méi)有 release() 函數(shù),,不會(huì)導(dǎo)致先前的內(nèi)存泄露問(wèn)題。其次,,由于 boost::scoped_ptr 是獨(dú)享所有權(quán)的,,所以明確拒絕用戶寫“my_memory2 = my_memory”之類的語(yǔ)句,可以緩解 std::auto_ptr 幾個(gè)惱人的問(wèn)題,。

    由于 boost::scoped_ptr 獨(dú)享所有權(quán),,當(dāng)我們真真需要復(fù)制智能指針時(shí),需求便滿足不了了,,如此我們?cè)僖胍粋€(gè)智能指針,,專門用于處理復(fù)制,參數(shù)傳遞的情況,,這便是如下的 boost::shared_ptr,。

 

4boost::shared_ptr

boost::shared_ptr 屬于 boost 庫(kù),,定義在 namespace boost 中,,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。在上面我們看到 boost::scoped_ptr 獨(dú)享所有權(quán),,不允許賦值,、拷貝,boost::shared_ptr 是專門用于共享所有權(quán)的,,由于要共享所有權(quán),,其在內(nèi)部使用了引用計(jì)數(shù)。boost::shared_ptr 也是用于管理單個(gè)堆內(nèi)存對(duì)象的,。

我們還是從代碼開始分析:

void TestSharedPtr(boost::shared_ptr<Simple> memory) {  // 注意:無(wú)需使用 reference ( const reference)

  memory->PrintSomething();

  std::cout << "TestSharedPtr UseCount: " << memory.use_count() << std::endl;

}

 

void TestSharedPtr2() {

  boost::shared_ptr<Simple> my_memory(new Simple(1));

  if (my_memory.get()) {

    my_memory->PrintSomething();

    my_memory.get()->info_extend = "Addition";

    my_memory->PrintSomething();

    (*my_memory).info_extend += " other";

    my_memory->PrintSomething();

  }

 

  std::cout << "TestSharedPtr2 UseCount: " << my_memory.use_count() << std::endl;

  TestSharedPtr(my_memory);

  std::cout << "TestSharedPtr2 UseCount: " << my_memory.use_count() << std::endl;

 

  //my_memory.release();// 編譯 error: 同樣,,shared_ptr 也沒(méi)有 release 函數(shù)

}

執(zhí)行結(jié)果為:

Simple: 1

PrintSomething:

PrintSomething: Addition

PrintSomething: Addition other

TestSharedPtr2 UseCount: 1

PrintSomething: Addition other

TestSharedPtr UseCount: 2

TestSharedPtr2 UseCount: 1

~Simple: 1

boost::shared_ptr 也可以很方便的使用。并且沒(méi)有 release() 函數(shù),。關(guān)鍵的一點(diǎn),,boost::shared_ptr 內(nèi)部維護(hù)了一個(gè)引用計(jì)數(shù),由此可以支持復(fù)制,、參數(shù)傳遞等,。boost::shared_ptr 提供了一個(gè)函數(shù) use_count() ,此函數(shù)返回 boost::shared_ptr 內(nèi)部的引用計(jì)數(shù)。查看執(zhí)行結(jié)果,,我們可以看到在 TestSharedPtr2 函數(shù)中,,引用計(jì)數(shù)為 1,傳遞參數(shù)后(此處進(jìn)行了一次復(fù)制),,在函數(shù)TestSharedPtr 內(nèi)部,,引用計(jì)數(shù)為2,在 TestSharedPtr 返回后,,引用計(jì)數(shù)又降低為 1,。當(dāng)我們需要使用一個(gè)共享對(duì)象的時(shí)候,boost::shared_ptr 是再好不過(guò)的了,。

在此,,我們已經(jīng)看完單個(gè)對(duì)象的智能指針管理,關(guān)于智能指針管理數(shù)組,,我們接下來(lái)講到,。

 

5boost::scoped_array

boost::scoped_array 屬于 boost 庫(kù),,定義在 namespace boost 中,,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。

    boost::scoped_array 便是用于管理動(dòng)態(tài)數(shù)組的,。跟 boost::scoped_ptr 一樣,,也是獨(dú)享所有權(quán)的。

我們還是從代碼開始分析:

void TestScopedArray() {

      boost::scoped_array<Simple> my_memory(new Simple[2]); // 使用內(nèi)存數(shù)組來(lái)初始化

      if (my_memory.get()) {

        my_memory[0].PrintSomething();

        my_memory.get()[0].info_extend = "Addition";

        my_memory[0].PrintSomething();

        (*my_memory)[0].info_extend += " other";            // 編譯 error,,scoped_ptr 沒(méi)有重載 operator*

        my_memory[0].release();                             // 同上,,沒(méi)有 release 函數(shù)

        boost::scoped_array<Simple> my_memory2;

        my_memory2 = my_memory;                             // 編譯 error,同上,,沒(méi)有重載 operator=

      }

    }

boost::scoped_array 的使用跟 boost::scoped_ptr 差不多,,不支持復(fù)制,并且初始化的時(shí)候需要使用動(dòng)態(tài)數(shù)組,。另外,,boost::scoped_array 沒(méi)有重載“operator*”,其實(shí)這并無(wú)大礙,,一般情況下,,我們使用 get() 函數(shù)更明確些。

    下面肯定應(yīng)該講 boost::shared_array 了,,一個(gè)用引用計(jì)數(shù)解決復(fù)制、參數(shù)傳遞的智能指針類,。

 

6,、boost::shared_array

boost::shared_array 屬于 boost 庫(kù),定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用,。

    由于 boost::scoped_array 獨(dú)享所有權(quán),,顯然在很多情況下(參數(shù)傳遞、對(duì)象賦值等)不滿足需求,,由此我們引入 boost::shared_array,。跟 boost::shared_ptr 一樣,內(nèi)部使用了引用計(jì)數(shù),。

我們還是從代碼開始分析:

void TestSharedArray(boost::shared_array<Simple> memory) {  // 注意:無(wú)需使用 reference ( const reference)

  std::cout << "TestSharedArray UseCount: " << memory.use_count() << std::endl;

}

 

void TestSharedArray2() {

  boost::shared_array<Simple> my_memory(new Simple[2]);

  if (my_memory.get()) {

    my_memory[0].PrintSomething();

    my_memory.get()[0].info_extend = "Addition 00";

    my_memory[0].PrintSomething();

    my_memory[1].PrintSomething();

    my_memory.get()[1].info_extend = "Addition 11";

    my_memory[1].PrintSomething();

    //(*my_memory)[0].info_extend += " other";  // 編譯 error,,scoped_ptr 沒(méi)有重載 operator*

  }

  std::cout << "TestSharedArray2 UseCount: " << my_memory.use_count() << std::endl;

  TestSharedArray(my_memory);

  std::cout << "TestSharedArray2 UseCount: " << my_memory.use_count() << std::endl;

}

執(zhí)行結(jié)果為:

Simple: 0

Simple: 0

PrintSomething:

PrintSomething: Addition 00

PrintSomething:

PrintSomething: Addition 11

TestSharedArray2 UseCount: 1

TestSharedArray UseCount: 2

TestSharedArray2 UseCount: 1

~Simple: 0

~Simple: 0

boost::shared_ptr 一樣,使用了引用計(jì)數(shù),,可以復(fù)制,,通過(guò)參數(shù)來(lái)傳遞。

 

至此,,我們講過(guò)的智能指針有 std::auto_ptr,、boost::scoped_ptrboost::shared_ptr,、boost::scoped_array,、boost::shared_array。這幾個(gè)智能指針已經(jīng)基本夠我們使用了,,90% 的使用過(guò)標(biāo)準(zhǔn)智能指針的代碼就這 5 種,。可如下還有兩種智能指針,,它們肯定有用,,但有什么用處呢,一起看看吧,。

 

7,、boost::weak_ptr

boost::weak_ptr 屬于 boost 庫(kù),定義在 namespace boost 中,,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用,。

在講 boost::weak_ptr 之前,讓我們先回顧一下前面講解的內(nèi)容,。似乎 boost::scoped_ptr,、boost::shared_ptr 這兩個(gè)智能指針就可以解決所有單個(gè)對(duì)象內(nèi)存的管理了,這兒還多出一個(gè) boost::weak_ptr,,是否還有某些情況我們沒(méi)納入考慮呢,?

回答:有。首先 boost::weak_ptr 是專門為 boost::shared_ptr 而準(zhǔn)備的,。有時(shí)候,,我們只關(guān)心能否使用對(duì)象,,并不關(guān)心內(nèi)部的引用計(jì)數(shù)。boost::weak_ptr boost::shared_ptr 的觀察者(Observer)對(duì)象,,觀察者意味著 boost::weak_ptr 只對(duì) boost::shared_ptr 進(jìn)行引用,,而不改變其引用計(jì)數(shù),當(dāng)被觀察的 boost::shared_ptr 失效后,,相應(yīng)的 boost::weak_ptr 也相應(yīng)失效,。

我們還是從代碼開始分析:

    void TestWeakPtr() {

      boost::weak_ptr<Simple> my_memory_weak;

      boost::shared_ptr<Simple> my_memory(new Simple(1));

 

      std::cout << "TestWeakPtr boost::shared_ptr UseCount: " << my_memory.use_count() << std::endl;

      my_memory_weak = my_memory;

      std::cout << "TestWeakPtr boost::shared_ptr UseCount: " << my_memory.use_count() << std::endl;

}

    執(zhí)行結(jié)果為:

Simple: 1

TestWeakPtr boost::shared_ptr UseCount: 1

TestWeakPtr boost::shared_ptr UseCount: 1

~Simple: 1

    我們看到,盡管被賦值了,,內(nèi)部的引用計(jì)數(shù)并沒(méi)有什么變化,,當(dāng)然,讀者也可以試試傳遞參數(shù)等其他情況,。

    現(xiàn)在要說(shuō)的問(wèn)題是,,boost::weak_ptr 到底有什么作用呢?從上面那個(gè)例子看來(lái),,似乎沒(méi)有任何作用,,其實(shí) boost::weak_ptr 主要用在軟件架構(gòu)設(shè)計(jì)中,可以在基類(此處的基類并非抽象基類,,而是指繼承于抽象基類的虛基類)中定義一個(gè) boost::weak_ptr,,用于指向子類的 boost::shared_ptr,這樣基類僅僅觀察自己的 boost::weak_ptr 是否為空就知道子類有沒(méi)對(duì)自己賦值了,,而不用影響子類 boost::shared_ptr 的引用計(jì)數(shù),,用以降低復(fù)雜度,更好的管理對(duì)象,。

 

    8,、boost::intrusive_ptr

boost::intrusive_ptr屬于 boost 庫(kù),定義在 namespace boost 中,,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用,。

講完如上 6 種智能指針后,對(duì)于一般程序來(lái)說(shuō) C++ 堆內(nèi)存管理就夠用了,,現(xiàn)在有多了一種 boost::intrusive_ptr,,這是一種插入式的智能指針,內(nèi)部不含有引用計(jì)數(shù),,需要程序員自己加入引用計(jì)數(shù),,不然編譯不過(guò)(⊙﹏⊙b汗)。個(gè)人感覺這個(gè)智能指針沒(méi)太大用處,,至少我沒(méi)用過(guò),。有興趣的朋友自己研究一下源代碼哦J

 

 

三,、總結(jié)

如上講了這么多智能指針,,有必要對(duì)這些智能指針做個(gè)總結(jié):

1,、在可以使用 boost 庫(kù)的場(chǎng)合下,拒絕使用 std::auto_ptr,,因?yàn)槠洳粌H不符合 C++ 編程思想,而且極容易出錯(cuò)[2],。

2,、在確定對(duì)象無(wú)需共享的情況下,使用 boost::scoped_ptr(當(dāng)然動(dòng)態(tài)數(shù)組使用 boost::scoped_array),。

3,、在對(duì)象需要共享的情況下,使用 boost::shared_ptr(當(dāng)然動(dòng)態(tài)數(shù)組使用 boost::shared_array),。

4,、在需要訪問(wèn) boost::shared_ptr 對(duì)象,而又不想改變其引用計(jì)數(shù)的情況下,,使用 boost::weak_ptr,,一般常用于軟件框架設(shè)計(jì)中。

5,、最后一點(diǎn),,也是要求最苛刻一點(diǎn):在你的代碼中,不要出現(xiàn) delete 關(guān)鍵字(或 C 語(yǔ)言的 free 函數(shù)),,因?yàn)榭梢杂弥悄苤羔樔ス芾怼?span lang=EN-US>

 

---------------------------------------

[1]參見《effective C++3rd)》,,條款06

[2]關(guān)于 boost 庫(kù)的使用,,可本博客另外一篇文章:《在 Windows 中編譯 boost1.42.0》,。

[3]讀者應(yīng)該看到了,在我所有的名字前,,都加了命名空間標(biāo)識(shí)符std::(或boost::),,這不是我不想寫 using namespace XXX 之類的語(yǔ)句,在大型項(xiàng)目中,,有可能會(huì)用到 N 個(gè)第三方庫(kù),,如果把命名空間全放出來(lái),命名污染(Naming conflicts)問(wèn)題很難避免,,到時(shí)要改回來(lái)是極端麻煩的事情,。當(dāng)然,如果你只是寫 Demo,,可以例外,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多