青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

SmartPtr
本博客已搬至:http://www.cnblogs.com/baiyanhuang/
posts - 29,comments - 176,trackbacks - 0
By SmartPtr(http://www.shnenglu.com/SmartPtr/)

auto_ptr是當前C++標準庫中提供的一種智能指針,或許相對于boost庫提供的一系列眼花繚亂的智能指針, 或許相對于Loki中那個無所不包的智能指針,這個不怎么智能的智能指針難免會黯然失色。誠然,auto_ptr有這樣那樣的不如人意,以至于程序員必須像使用”裸“指針那樣非常小心的使用它才能保證不出錯,以至于它甚至無法適用于同是標準庫中的那么多的容器和一些算法,但即使如此,我們仍然不能否認這個小小的auto_ptr所蘊含的價值與理念。
  auto_ptr的出現,主要是為了解決“被異常拋出時發生資源泄漏”的問題。即如果我們讓資源在局部對象構造時分配,在局部對象析構時釋放。這樣即使在函數執行過程時發生異常退出,也會因為異常能保證局部對象被析構從而保證資源被釋放。auto_ptr就是基于這個理念而設計, 這最早出現在C++之父Bjarne Stroustrup的兩本巨著TC++PL和D&E中,其主題為"resource acquisition is initialization"(raii,資源獲取即初始化),然后又在Scott Meyer的<<More Effective C++>>中相關章節的推動下,被加入了C++標準庫。
  下面我就列出auto_ptr的源代碼,并詳細講解每一部分。因為標準庫中的代碼要考慮不同編譯器支持標準的不同而插入了不少預編譯判斷,而且命名可讀性不是很強(即使是侯捷老師推薦的SGI版本的stl,可讀性也不盡如人意), 這里我用了Nicolai M. Josuttis(<<The C++ standard library>>作者)寫的一個auto_ptr的版本,并做了少許格式上的修改以易于分析閱讀。

 

namespace std
{
 template
<class T>
 
class auto_ptr 
 {
 
private:
  T
* ap; 
 
public:

  
// constructor & destructor ----------------------------------- (1)
  explicit auto_ptr (T* ptr = 0throw() : ap(ptr){}

  
~auto_ptr() throw() 
  {
   delete ap;
  }

  
  
// Copy & assignment --------------------------------------------(2)
  auto_ptr (auto_ptr& rhs) throw() :ap(rhs.release()) {}
  template
<class Y>  
  auto_ptr (auto_ptr
<Y>& rhs) throw() : ap(rhs.release()) { }

  auto_ptr
& operator= (auto_ptr& rhs) throw() 
  {
   reset(rhs.release());
   
return *this;
  }
  template
<class Y>
  auto_ptr
& operator= (auto_ptr<Y>& rhs) throw() 
  {
   reset(rhs.release());
   
return *this;
  }

  
// Dereference----------------------------------------------------(3)
  T& operator*() const throw() 
  {
   
return *ap;
  }
  T
* operator->() const throw() 
  {
   
return ap;
  }

  
// Helper functions------------------------------------------------(4)
  
// value access
  T* get() const throw() 
  {
   
return ap;
  }

  
// release ownership
  T* release() throw()
  {
   T
* tmp(ap);
   ap 
= 0;
   
return tmp;
  }

  
// reset value
  void reset (T* ptr=0throw() 
  {
   
if (ap != ptr) 
   {
    delete ap;
    ap 
= ptr;
   }
  }

  
// Special conversions-----------------------------------------------(5)
  template<class Y>
  
struct auto_ptr_ref
  {
   Y
* yp;
   auto_ptr_ref (Y
* rhs) : yp(rhs) {}
  };

  auto_ptr(auto_ptr_ref
<T> rhs) throw() : ap(rhs.yp) { }
  auto_ptr
& operator= (auto_ptr_ref<T> rhs) throw() 
  {  
   reset(rhs.yp);
   
return *this;
  }
  template
<class Y>
  
operator auto_ptr_ref<Y>() throw() 
  {
   
return auto_ptr_ref<Y>(release());
  }
  template
<class Y>
  
operator auto_ptr<Y>() throw()
  {
   
return auto_ptr<Y>(release());
  }
 };
}


1 構造函數與析構函數
auto_ptr在構造時獲取對某個對象的所有權(ownership),在析構時釋放該對象。我們可以這樣使用auto_ptr來提高代碼安全性:
int* p = new int(0);
auto_ptr<int> ap(p);
從此我們不必關心應該何時釋放p, 也不用擔心發生異常會有內存泄漏。
這里我們有幾點要注意:
1) 因為auto_ptr析構的時候肯定會刪除他所擁有的那個對象,所有我們就要注意了,一個蘿卜一個坑,兩個auto_ptr不能同時擁有同一個對象。像這樣:
int* p = new int(0);
auto_ptr<int> ap1(p);
auto_ptr<int> ap2(p);
因為ap1與ap2都認為指針p是歸它管的,在析構時都試圖刪除p, 兩次刪除同一個對象的行為在C++標準中是未定義的。所以我們必須防止這樣使用auto_ptr.
2) 考慮下面這種用法:
int* pa = new int[10];
auto_ptr<int> ap(pa);
因為auto_ptr的析構函數中刪除指針用的是delete,而不是delete [],所以我們不應該用auto_ptr來管理一個數組指針。
3) 構造函數的explicit關鍵詞有效阻止從一個“裸”指針隱式轉換成auto_ptr類型。
4) 因為C++保證刪除一個空指針是安全的, 所以我們沒有必要把析構函數寫成:
~auto_ptr() throw()
{
 if(ap) delete ap;
}

2 拷貝構造與賦值
與引用計數型智能指針不同的,auto_ptr要求其對“裸”指針的完全占有性。也就是說一個”裸“指針不能同時被兩個以上的auto_ptr所擁有。那么,在拷貝構造或賦值操作時,我們必須作特殊的處理來保證這個特性。auto_ptr的做法是“所有權轉移”,即拷貝或賦值的源對象將失去對“裸”指針的所有權,所以,與一般拷貝構造函數,賦值函數不同, auto_ptr的拷貝構造函數,賦值函數的參數為引用而不是常引用(const reference).當然,一個auto_ptr也不能同時擁有兩個以上的“裸”指針,所以,拷貝或賦值的目標對象將先釋放其原來所擁有的對象。
這里的注意點是:
1) 因為一個auto_ptr被拷貝或被賦值后, 其已經失去對原對象的所有權,這個時候,對這個auto_ptr的提領(dereference)操作是不安全的。如下:
int* p = new int(0);
auto_ptr<int> ap1(p);
auto_ptr<int> ap2 = ap1;
cout<<*ap1; //錯誤,此時ap1只剩一個null指針在手了
這種情況較為隱蔽的情形出現在將auto_ptr作為函數參數按值傳遞,因為在函數調用過程中在函數的作用域中會產生一個局部對象來接收傳入的auto_ptr(拷貝構造),這樣,傳入的實參auto_ptr就失去了其對原對象的所有權,而該對象會在函數退出時被局部auto_ptr刪除。如下:
void f(auto_ptr<int> ap){cout<<*ap;}
auto_ptr<int> ap1(new int(0));
f(ap1);
cout<<*ap1; //錯誤,經過f(ap1)函數調用,ap1已經不再擁有任何對象了。
因為這種情況太隱蔽,太容易出錯了, 所以auto_ptr作為函數參數按值傳遞是一定要避免的。或許大家會想到用auto_ptr的指針或引用作為函數參數或許可以,但是仔細想想,我們并不知道在函數中對傳入的auto_ptr做了什么, 如果當中某些操作使其失去了對對象的所有權, 那么這還是可能會導致致命的執行期錯誤。 也許,用const reference的形式來傳遞auto_ptr會是一個不錯的選擇。

2)我們可以看到拷貝構造函數與賦值函數都提供了一個成員模板在不覆蓋“正統”版本的情況下實現auto_ptr的隱式轉換。如我們有以下兩個類
class base{};
class derived: public base{};
那么下列代碼就可以通過,實現從auto_ptr<derived>到auto_ptr<base>的隱式轉換,因為derived*可以轉換成base*類型
auto_ptr<base> apbase = auto_ptr<derived>(new derived);

3) 因為auto_ptr不具有值語義(value semantic), 所以auto_ptr不能被用在stl標準容器中。
所謂值語義,是指符合以下條件的類型(假設有類A):
A a1;
A a2(a1);
A a3;
a3 = a1;
那么
a2 == a1, a3 == a1
很明顯,auto_ptr不符合上述條件,而我們知道stl標準容器要用到大量的拷貝賦值操作,并且假設其操作的類型必須符合以上條件。


3 提領操作(dereference)
提領操作有兩個操作, 一個是返回其所擁有的對象的引用, 另一個是則實現了通過auto_ptr調用其所擁有的對象的成員。如:
struct A
{
 void f();
}
auto_ptr<A> apa(new A);
(*apa).f();
apa->f();
當然, 我們首先要確保這個智能指針確實擁有某個對象,否則,這個操作的行為即對空指針的提領是未定義的。

4 輔助函數
1) get用來顯式的返回auto_ptr所擁有的對象指針。我們可以發現,標準庫提供的auto_ptr既不提供從“裸”指針到auto_ptr的隱式轉換(構造函數為explicit),也不提供從auto_ptr到“裸”指針的隱式轉換,從使用上來講可能不那么的靈活, 考慮到其所帶來的安全性還是值得的。
2) release,用來轉移所有權
3) reset,用來接收所有權,如果接收所有權的auto_ptr如果已經擁有某對象, 必須先釋放該對象。

5 特殊轉換
這里提供一個輔助類auto_ptr_ref來做特殊的轉換,按照標準的解釋, 這個類及下面4個函數的作用是:使我們得以拷貝和賦值non-const auto_ptrs, 卻不能拷貝和賦值const auto_ptrs. 我無法非常準確的理解這兩句話的意義,但根據我們觀察與試驗,應該可以這樣去理解:沒有這些代碼,我們本來就可以拷貝和賦值non-const的auto_ptr和禁止拷貝和賦值const的auto_ptr的功能, 只是無法拷貝和賦值臨時的auto_ptr(右值), 而這些輔助代碼提供某些轉換,使我們可以拷貝和賦值臨時的auto_ptr,但并沒有使const的auto_ptr也能被拷貝和賦值。如下:
auto_ptr<int> ap1 = auto_ptr<int>(new int(0));
auto_ptr<int>(new int(0))是一個臨時對象,一個右值,一般的拷貝構造函數當然能拷貝右值,因為其參數類別必須為一個const reference, 但是我們知道,auto_ptr的拷貝函數其參數類型為reference,所以,為了使這行代碼能通過,我們引入auto_ptr_ref來實現從右值向左值的轉換。其過程為:
1) ap1要通過拷貝 auto_ptr<int>(new int(0))來構造自己
2) auto_ptr<int>(new int(0))作為右值與現有的兩個拷貝構造函數參數類型都無法匹配,也無法轉換成該種參數類型
3) 發現輔助的拷貝構造函數auto_ptr(auto_ptr_ref<T> rhs) throw()
4) 試圖將auto_ptr<int>(new int(0))轉換成auto_ptr_ref<T>
5) 發現類型轉換函數operator auto_ptr_ref<Y>() throw(), 轉換成功,從而拷貝成功。
從而通過一個間接類成功的實現了拷貝構造右值(臨時對象)
同時,這個輔助方法不會使const auto_ptr被拷貝, 原因是在第5步, 此類型轉換函數為non-const的,我們知道,const對象是無法調用non-const成員的, 所以轉換失敗。當然, 這里有一個問題要注意, 假設你把這些輔助轉換的代碼注釋掉,該行代碼還是可能成功編譯,這是為什么呢?debug一下, 我們可以發現只調用了一次構造函數,而拷貝構造函數并沒有被調用,原因在于編譯器將代碼優化掉了。這種類型優化叫做returned value optimization,它可以有效防止一些無意義的臨時對象的構造。當然,前提是你的編譯器要支持returned value optimization。

  可見,auto_ptr短短百來行的代碼,還是包含了不少"玄機"的。 

posted on 2007-07-05 17:48 SmartPtr 閱讀(12092) 評論(3)  編輯 收藏 引用

FeedBack:
# re: auto_ptr解析 [未登錄]
2007-07-14 22:08 | walkspeed
多看代碼,多分析代碼,學習代碼中的實現。不錯。  回復  更多評論
  
# re: auto_ptr解析 [未登錄]
2008-01-22 22:36 | ron
呵呵,正愁不知道auto_ptr的原理呢, 現在想想,該方法實現的挺巧妙的,
有一點,就是在special conversion 下的
operator auto_ptr<Y>() throw()
是什么時候會用的到的呢?  回復  更多評論
  
# re: auto_ptr解析
2013-10-10 14:33 | lzxbill7
@ron
同疑惑這里,至少沒在auto_ptr內部使用。唯一想到的是將auto_ptr<T>轉變為auto_ptr<Y>時,這就得讓使用者顯示轉化了。  回復  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美日韩直播| 久久―日本道色综合久久| 欧美国产在线电影| 亚洲黄色成人| 亚洲人成网站在线观看播放| 久久综合九色欧美综合狠狠| 欧美在线1区| 亚洲精品日韩在线观看| 一本久久a久久精品亚洲| 国产精品免费在线| 免费观看成人鲁鲁鲁鲁鲁视频| 久久综合一区二区| 一区二区三区黄色| 欧美一区二区三区视频免费播放 | 一本色道久久99精品综合| 国产精品久久久久久久久搜平片| 久久久精品性| 欧美激情一区二区三区在线视频| 亚洲免费网站| 久热综合在线亚洲精品| 亚洲一区二区免费看| 性色av一区二区三区在线观看| 亚洲欧洲一区二区三区| 亚洲视频精选在线| 亚洲电影专区| 午夜精品久久久久影视| 亚洲精品一区二区网址| 午夜精品久久久久久久久久久久久 | 最新成人av在线| 一区二区成人精品 | 日韩视频一区二区三区| 午夜激情久久久| 日韩午夜av| 久久成人综合网| 亚洲专区一二三| 欧美.www| 老司机免费视频一区二区三区| 欧美日韩精品中文字幕| 欧美国产日韩a欧美在线观看| 国产精品久久久久久久久婷婷| 亚洲电影中文字幕| 国产综合久久久久影院| 亚洲午夜精品久久久久久浪潮| 91久久国产自产拍夜夜嗨| 性欧美超级视频| 欧美一级播放| 国产精品国产三级国产aⅴ入口| 久久综合电影| 国产亚洲精品bt天堂精选| 一区二区三欧美| 日韩一级免费| 欧美高清不卡在线| 欧美高清视频一区| 怡红院精品视频| 欧美在线你懂的| 久久久蜜桃一区二区人| 国产视频自拍一区| 香蕉乱码成人久久天堂爱免费| 亚洲女性喷水在线观看一区| 欧美日韩免费在线观看| 99re热这里只有精品视频 | 国产精品人人做人人爽| 欧美亚洲免费在线| 国产麻豆精品久久一二三| 亚洲在线电影| 亚洲欧美日韩系列| 国产精品永久免费| 久久国产精品亚洲77777| 久热精品视频在线观看| 韩国欧美一区| 欧美bbbxxxxx| 亚洲理论在线| 亚洲综合第一| 国产一区二区主播在线| 久久国产精品一区二区三区四区| 久久人人爽爽爽人久久久| 激情亚洲网站| 欧美第一黄色网| 一本色道久久综合狠狠躁篇怎么玩| 亚洲天堂第二页| 国产一区二区三区精品久久久| 久久九九精品99国产精品| 欧美成人中文字幕| 在线综合亚洲| 国产欧美日韩一区二区三区| 久久久www成人免费无遮挡大片| 欧美成人一区二区| 在线一区二区日韩| 国产婷婷97碰碰久久人人蜜臀| 久久亚洲国产精品日日av夜夜| 亚洲国产日韩欧美综合久久| 亚洲一区尤物| 精品88久久久久88久久久| 欧美经典一区二区| 午夜精品一区二区三区在线播放| 欧美国产日本| 亚洲欧美中文日韩在线| 在线观看国产欧美| 欧美午夜一区二区三区免费大片| 久久久国产亚洲精品| 91久久夜色精品国产网站| 欧美一区二区三区喷汁尤物| 91久久精品国产91性色tv| 国产精品色午夜在线观看| 麻豆精品一区二区av白丝在线| 99一区二区| 亚洲第一精品夜夜躁人人躁| 午夜视黄欧洲亚洲| 亚洲精选成人| 黑人巨大精品欧美黑白配亚洲 | 欧美欧美天天天天操| 午夜精品一区二区三区在线视| 亚洲激情国产| 欧美xxxx在线观看| 欧美在线免费观看视频| 中日韩高清电影网| 亚洲缚视频在线观看| 国产色产综合色产在线视频| 欧美日本一区二区三区| 另类专区欧美制服同性| 欧美在线看片a免费观看| 亚洲一区二区三区高清 | 欧美中文日韩| 亚洲欧美激情四射在线日| 一区二区三区成人| 亚洲另类视频| 亚洲国产精品专区久久| 免费日韩视频| 欧美+日本+国产+在线a∨观看| 欧美一区午夜视频在线观看| 亚洲一区二区三区三| 欧美日韩中文字幕精品| 欧美激情国产日韩| 欧美激情第10页| 欧美.www| 欧美成人一区二区在线| 免费成人毛片| 欧美大成色www永久网站婷| 欧美成人免费大片| 欧美国产极速在线| 欧美精品激情blacked18| 欧美激情一区二区三区成人| 欧美大片一区二区三区| 欧美激情综合色| 欧美日韩午夜在线视频| 欧美性猛交一区二区三区精品| 欧美深夜影院| 国产精品一区二区三区四区五区| 国产精品一区毛片| 国产日韩精品一区二区| 狠狠色丁香久久综合频道| 黄色工厂这里只有精品| 亚洲黄色一区| av不卡在线观看| 亚洲一区中文| 久久久久久亚洲精品不卡4k岛国| 久久另类ts人妖一区二区| 亚洲成人资源网| 99热这里只有成人精品国产| 亚洲小说春色综合另类电影| 欧美一区二区在线| 免费观看欧美在线视频的网站| 欧美精品免费视频| 国产精品视频男人的天堂| 国产网站欧美日韩免费精品在线观看 | 亚洲视频免费| 欧美综合二区| 欧美α欧美αv大片| 欧美日韩在线一区| 国产在线不卡| 亚洲午夜av电影| 久热精品视频在线| 日韩视频免费在线观看| 亚洲专区在线视频| 免费看亚洲片| 国产精品一区二区在线观看网站| **性色生活片久久毛片| 亚洲午夜黄色| 欧美成人日本| 午夜在线精品偷拍| 欧美国产欧美亚洲国产日韩mv天天看完整| 欧美揉bbbbb揉bbbbb| 激情视频一区| 欧美一区二区免费视频| 亚洲成色精品| 久久国产天堂福利天堂| 欧美日韩国产一区精品一区| 国产一区二区三区免费观看| 日韩午夜电影| 欧美成人精品影院| 午夜亚洲激情| 欧美日韩另类字幕中文| 精品69视频一区二区三区| 欧美一区二区在线观看| 91久久在线视频| 另类尿喷潮videofree| 国产日韩精品久久| 亚洲欧美清纯在线制服| 亚洲精品视频在线看| 欧美+日本+国产+在线a∨观看|