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

分享

C 智能指針詳解

 大老淵 2016-06-02
智能指針內(nèi)容很多,,重點是基本用法,。
復制代碼
#include 
class CBase: public boost::enable_shared_from_this 
{
public:
virtual void f(){}//必須有個虛函數(shù)才能向上向下轉(zhuǎn)換。
}
typedef boost::shared_ptr CBasePtr;
class CChild: public CBase
{}
typedef boost::shared_ptr CChildPtr;
void main()
{
 CBasePtr ptrBase = boost::make_shared();
 //CBasePtr ptrBase = CBasePtr(new CBase());
 
// 向下轉(zhuǎn)換
 CChildPtr ptrChild = boost::dynamic_pointer_cast(ptrBase);
 // 向上轉(zhuǎn)換
 CBasePtr ptrXXX = ptrChild;
 // 普通轉(zhuǎn)換
 CChildPtr ptrXX = CChildPtr(dynamic_cast(ptrXXX.get()));
}
復制代碼
暫時學會這些用法即可,。
url:http://greatverve.cnblogs.com/p/smart-ptr.html

C++ 智能指針詳解

 

一,、簡介

由于 C++ 語言沒有自動內(nèi)存回收機制,,程序員每次 new 出來的內(nèi)存都要手動 delete。程序員忘記 delete,,流程太復雜,,最終導致沒有 delete,異常導致程序過早退出,,沒有執(zhí)行 delete 的情況并不罕見,。

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

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

 

二,、具體使用

1、總括

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

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

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

我們編寫一個測試類來輔助分析:

class Simple {

 public:

  Simple(int param = 0) {

    number = param;

    std::cout < 'simple:="" '="">< number=""><> 

  }

 

  ~Simple() {

    std::cout < '~simple:="" '="">< number=""><>

  }

 

  void PrintSomething() {

    std::cout < 'printsomething:="" '="">< info_extend.c_str()=""><>

  }

 

  std::string info_extend;

  int number;

};

 

2,、std::auto_ptr

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

我們從代碼開始分析:

void TestAutoPtr() {

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

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

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

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

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

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

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

  }

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

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

Simple: 1

PrintSomething:

PrintSomething: Addition

PrintSomething: Addition other

~Simple: 1

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

 

其實好景不長,,我們看看如下的另一個例子:

void TestAutoPtr2() {

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

  if (my_memory.get()) {

    std::auto_ptr my_memory2;   // 創(chuàng)建一個新的 my_memory2 對象

    my_memory2 = my_memory;             // 復制舊的 my_memory  my_memory2

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

    my_memory->PrintSomething();        // 崩潰

  }

}

最終如上代碼導致崩潰,如上代碼時絕對符合 C++ 編程思想的,,居然崩潰了,,跟進std::auto_ptr 的源碼后,我們看到,,罪魁禍首是“my_memory2 = my_memory”,,這行代碼,my_memory2 完全奪取了 my_memory 的內(nèi)存管理所有權(quán),,導致 my_memory 懸空,,最后使用時導致崩潰。

所以,,使用 std::auto_ptr 時,,絕對不能使用“operator=”操作符。作為一個庫,,不允許用戶使用,,確沒有明確拒絕[1],多少會覺得有點出乎預料,。

 

看完 std::auto_ptr 好景不長的第一個例子后,,讓我們再來看一個:

void TestAutoPtr3() {

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

 

  if (my_memory.get()) {

    my_memory.release();

  }

}

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

Simple: 1

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

正確的代碼應該為:

void TestAutoPtr3() {

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

  if (my_memory.get()) {

    Simple* temp_memory = my_memory.release();

    delete temp_memory;

  }

}

void TestAutoPtr3() {

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

  if (my_memory.get()) {

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

  }

}

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

總結(jié):std::auto_ptr 可用來管理單個對象的對內(nèi)存,但是,,請注意如下幾點:

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

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

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

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

(5)    ……

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

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

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

 

3,、boost::scoped_ptr

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

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

void TestScopedPtr() {

  boost::scoped_ptr 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 沒有 release 函數(shù)

    std::auto_ptr my_memory2;

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

  }

}

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

    由于 boost::scoped_ptr 獨享所有權(quán),,當我們真真需要復制智能指針時,,需求便滿足不了了,如此我們再引入一個智能指針,,專門用于處理復制,,參數(shù)傳遞的情況,這便是如下的boost::shared_ptr,。

 

4,、boost::shared_ptr

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

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

void TestSharedPtr(boost::shared_ptr memory) {  // 注意:無需使用 reference ( const reference)

  memory->PrintSomething();

  std::cout < 'testsharedptr="" usecount:="" '="">< memory.use_count()=""><>

}

 

void TestSharedPtr2() {

  boost::shared_ptr 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()=""><>

  TestSharedPtr(my_memory);

  std::cout < 'testsharedptr2="" usecount:="" '="">< my_memory.use_count()=""><>

 

  //my_memory.release();// 編譯 error: 同樣,,shared_ptr 也沒有 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 也可以很方便的使用,。并且沒有 release() 函數(shù)。關鍵的一點,,boost::shared_ptr 內(nèi)部維護了一個引用計數(shù),,由此可以支持復制、參數(shù)傳遞等,。boost::shared_ptr 提供了一個函數(shù) use_count() ,,此函數(shù)返回 boost::shared_ptr 內(nèi)部的引用計數(shù),。查看執(zhí)行結(jié)果,我們可以看到在 TestSharedPtr2 函數(shù)中,,引用計數(shù)為 1,,傳遞參數(shù)后(此處進行了一次復制),在函數(shù)TestSharedPtr 內(nèi)部,,引用計數(shù)為2,,在 TestSharedPtr 返回后,引用計數(shù)又降低為 1,。當我們需要使用一個共享對象的時候,,boost::shared_ptr 是再好不過的了。

在此,,我們已經(jīng)看完單個對象的智能指針管理,,關于智能指針管理數(shù)組,我們接下來講到,。

 

5,、boost::scoped_array

boost::scoped_array 屬于 boost 庫,定義在 namespace boost 中,,包含頭文件#include 便可以使用,。

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

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

void TestScopedArray() {

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

      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';            // 編譯 errorscoped_ptr 沒有重載operator*

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

        boost::scoped_array my_memory2;

        my_memory2 = my_memory;                             // 編譯 error,,同上,沒有重載 operator=

      }

    }

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

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

 

6,、boost::shared_array

boost::shared_array 屬于 boost 庫,,定義在 namespace boost 中,,包含頭文件#include 便可以使用。

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

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

void TestSharedArray(boost::shared_array memory) {  // 注意:無需使用 reference (const reference)

  std::cout < 'testsharedarray="" usecount:="" '="">< memory.use_count()=""><>

}

 

void TestSharedArray2() {

  boost::shared_array 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 沒有重載 operator*

  }

  std::cout < 'testsharedarray2="" usecount:="" '="">< my_memory.use_count()=""><>

  TestSharedArray(my_memory);

  std::cout < 'testsharedarray2="" usecount:="" '="">< my_memory.use_count()=""><>

}

執(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 一樣,,使用了引用計數(shù),可以復制,,通過參數(shù)來傳遞,。

 

至此,我們講過的智能指針有std::auto_ptr,、boost::scoped_ptr,、boost::shared_ptrboost::scoped_array,、boost::shared_array,。這幾個智能指針已經(jīng)基本夠我們使用了,90% 的使用過標準智能指針的代碼就這 5 種,??扇缦逻€有兩種智能指針,它們肯定有用,,但有什么用處呢,,一起看看吧。

 

7,、boost::weak_ptr

boost::weak_ptr 屬于 boost 庫,,定義在 namespace boost 中,包含頭文件#include 便可以使用,。

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

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

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

    void TestWeakPtr() {

      boost::weak_ptr my_memory_weak;

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

 

      std::cout < 'testweakptr="" boost::shared_ptr="" usecount:="" '="">< my_memory.use_count()=""><>

      my_memory_weak = my_memory;

      std::cout < 'testweakptr="" boost::shared_ptr="" usecount:="" '="">< my_memory.use_count()=""><>

}

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

Simple: 1

TestWeakPtr boost::shared_ptr UseCount: 1

TestWeakPtr boost::shared_ptr UseCount: 1

~Simple: 1

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

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

 

    8,、boost::intrusive_ptr

boost::intrusive_ptr屬于 boost 庫,,定義在 namespace boost 中,包含頭文件#include 便可以使用,。

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

 

 

三、總結(jié)

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

1,、在可以使用 boost 庫的場合下,拒絕使用 std::auto_ptr,,因為其不僅不符合 C++ 編程思想,,而且極容易出錯[2]

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

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

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

5、最后一點,,也是要求最苛刻一點:在你的代碼中,,不要出現(xiàn) delete 關鍵字(或 C 語言的free 函數(shù)),因為可以用智能指針去管理,。

 

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

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

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

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


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

error C2683: “dynamic_cast”:“XXX”不是多態(tài)類型

 

使用dynamic_cast會引發(fā)效率上的擔憂,但是有時候這是必要的,而有時候,,這是必須的,,在自己不預加運行時識別策略的時候,如果要使用運行時處理機制,,通過dynamic_cast判斷指針或檢測異常是一個非常直觀的想法,,而且不少時候這也很有效。

但對dynamic_cast理解不夠深入會遇到這樣的麻煩:

 

class Bast
{

}
;

class Test    :public Bast
{
    
}
;

int _tmain(int argc, _TCHAR* argv[])
{
    Bast
*    bt    = new Test();
    Test
*    tt    = dynamic_castTest*>(bt);
    
return 0;
}

 

編譯器抱怨說error C2683: “dynamic_cast”:“Bast”不是多態(tài)類型,。

在我的編譯器上調(diào)試這種情況發(fā)現(xiàn),,子類里明確包含了基類,但是一個基類指針指向子類的時候,,無法識別出來子類的附加信息,。也就是說,在沒有虛函數(shù)參與的時候,,并沒有神秘的vtable存在,,c++對象模型里似乎也提到了(我記不清是不是這本書了,sorry)編譯器實現(xiàn)虛函數(shù)靠的是vtable策略,,但是這話的深層含義卻是如果沒有虛函數(shù)存在,,編譯器沒有必要浪費空間實現(xiàn)一個虛指針、vtable(我開始脊背發(fā)涼了),??磥泶髱煹拿恳痪湓挾家屑氀芯俊?/p>

當把基類改成這樣:

 

class Bast
{
    
virtual    void    dosomething(){}
}
;

 

調(diào)試發(fā)現(xiàn)任何時候,,虛指針都存在,,也就是說,運行時識別技術(shù)可以生效,。

也就是說,,如果希望使用dynamic_cast技術(shù)或者你不得不使用dynamic_cast技術(shù),那應該確保你在多態(tài)類上使用它(也就是你的繼承體系里有虛函數(shù)),。
end

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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多