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

asm, c, c++ are my all
-- Core In Computer
posts - 139,  comments - 123,  trackbacks - 0

[轉]智能指針與微妙的隱式轉換

??? C++
雖然是強類型語言,但是卻還不如 Java C# 那么足夠的強類型,原因是允許的隱式轉換太多

  • C 語言繼承下來的基本類型之間的隱式轉換
  • T* 指針到 void* 的隱式轉換
  • non-explicit constructor 接受一個參數的隱式轉換
  • 從子類到基類的隱式轉換 ( 安全)
  • const non-const 的同類型的隱式轉換 ( 安全 )

除開上面的五種隱式轉換外, C++ 的編譯器還非常聰明,當沒法直接隱式轉換的時候,它會嘗試間接的方式隱式轉換,這使得有時候的隱式轉換非常的微妙,一個誤用會被編譯器接受而會出現意想不到的結果。例如假設類 A 有一個 non-explicit constructor ,唯一的參數是類 B ,而類 B 也有一個 non-explicit constructor 接受類型 C ,那么當試圖用類型 C 的實例初始化類 A 的時候,編譯器發現沒有直接從類型 C 構造的過程,但是呢,由于類 B 可以被接受,而類型 C 又可以向類型 B 隱式轉換,因此從 C->B->A 的路就通暢了。這樣的隱式轉換多數時候沒什么大礙,但是不是我們想要的,因為它可能造成一些微妙的 bug 而難以捕捉。

?

為了在培訓的時候展示棧上析構函數的特點和自動資源管理,準備下面的一個例子,結果測試的時候由于誤用而發現一些問題。 ( 測試的 IDE Visual Studio 2005)

class A

{

public:

A(){ a = 100; }

int a;

void f();

};

?

A * pa = new A();

std::auto_ptr<A>? p = pa;? // 無意這樣使用的,本意是 std::auto_ptr<A> p(pa)

p->f();

?

這個寫法是拷貝構造函數的形式,顯然從 T* 是不能直接拷貝構造的 auto_ptr 的,但是編譯器會嘗試其他的路徑來轉換成 auto_ptr 來拷貝構造,因此如果存在一個中間的 ,這個類能接受從 T* 的構造,而 同時auto_ptr也能接受從類X 的構造,那編譯器就會很高興的生成這樣的代碼。

這段代碼在 VC6 上是通不過的,因為 VC6 auto_ptr 實現就只有一個接受 T* 指針的 explicit constructor .

但是 C++ Standard 的修正規范中,要求 auto_ptr 還應該有個接受 auto_ptr_ref constructor 。那么這個 auto_ptr_ref 是什么呢?按照 C++ Standard 的解釋 :

Template auto_ptr_ref holds a reference to an auto_ptr. It is used by the auto_ptr conversions to allow auto_ptr objects to be passed to and returned from functions.

有興趣可以參考 Scott Meyers " auto_ptr update page "? ( http://www.awprofessional.com/content/images/020163371X/autoptrupdate%5Cauto_ptr_update.html ?)講訴auto_ptr的歷史.

?

再回到前面的代碼,本來應該是通不過的編譯,但是 VC2005 的編譯器卻沒有任何怨言的通過 ( 即使把警告等級設置到 4) 。結果運行的時候卻崩潰了,出錯在 auto_ptr 的析構函數 ,delete 的指針所指向地址是 100 ,而如果在 p->f() 后面加上一句 cout << pa->a << endl; 發現輸出結果為 0 為什么會這樣,原因就是前面所訴的間接的隱式轉換,這與 VC 2006 auto_ptr auto_ptr_ref 實現有關,看看 P.J.Plauger 是怎么實現的 :

// auto_ptr_ref

template<class _Ty>

struct auto_ptr_ref

{

// proxy reference for auto_ptr copying

auto_ptr_ref(void *_Right)

: _Ref(_Right)

{?? // construct from generic pointer to auto_ptr ptr

}

void *_Ref;// generic pointer to auto_ptr ptr

};

?

// construct auto_ptr from an auto_ptr_ref object

auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()

{

// construct by assuming pointer from _Right auto_ptr_ref

_Ty **_Pptr = (_Ty **)_Right._Ref;

_Ty *_Ptr = *_Pptr;

*_Pptr = 0;

// release old

_Myptr = _Ptr;

// reset this

}

?

這樣代碼通過編譯的原因也就清楚了, A* -> void * -> auto_ptr_ref -> auto_ptr -> copy constructor -> accept. 好長的隱式轉換鏈 , -_-, C++ 編譯器太聰明了。

那么為什么最后會出現指針被破壞的結果呢,原因在 auto_ptr 的實現,因為按照 C++ Standard 要求, auto_ptr_ref 應該是包含一個 auto_ptr 的引用,因此 auto_ptr 的構造函數也就假設了 auto_ptr_ref 的成員 _Ref 是一個指向 auto_ptr 的指針。 auto_ptr 中只有一個成員就是 A* 的指針,因此指向 auto_ptr 對象的指針相當于就是個 A** 指針,因此上面 auto_ptr auto_ptr_ref 構造的代碼是合理的。 但是由于罪惡的 void* 造成了一條非常寬敞的隱式轉換的道路, A* 指針也能夠被接受,因此把 A* 當作 A** 來使用,結果可想而知, A* 指向地址的前 4 個字節 ( 因為 32 OS) 被拷貝出來,而這四個字節被賦值為 0( *_Pptr=0 ) 。 所以出現了最后的結果是 _Myptr 值為 100 ,而 pa->a 0

如果要正確執行結果,只要保證是個 A** 指針就行了,有兩個方法

第一, auto_ptr_ref 所包含的引用是指向的 auto_ptr 對象

A * p = new A();

std::auto_ptr<A> pt( new A() );

std::auto_ptr_ref<A> ra( pt );

std::auto_ptr<A> pb = ra ;

pb->f();

?

第二,直接用二級指針

A * p = new A();

std::auto_ptr<A> pb = &p;? // 這句話后 , p 將等于 0

pb->f();

?

當然第二種是利用了 VC2005 的實現而造出來的,看著很別扭 ,:) 我不明白 P.J.Plauger 為什么用 void * ,而不是用 auto_ptr<T>& ,因為任何指針都能隱式轉換為 void * ,這樣的危險性大多了。并且如果用了 auto_ptr<T>& ,從 auto_ptr_ref 構造也容易寫得更簡單清楚,看看以前的實現方式吧,仍然是 P.J.Plauger 的,但是版本低了點:

template<class _Ty>

struct auto_ptr_ref

{

// proxy reference for auto_ptr copying

?

auto_ptr_ref(auto_ptr<_Ty>& _Right)

: _Ref(_Right)

{

// construct from compatible auto_ptr

}

auto_ptr<_Ty>& _Ref;

// reference to constructor argument

};

auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0()

: _Myptr(_Right._Ref.release())

{

// construct by assuming pointer from _Right auto_ptr_ref

}

?

這樣的實現方法,顯然不能接受任何指針的隱式轉換,也就防止一開始的那種錯誤寫法,并且也是符合 C++ Standard 的要求的。

SGI STL auto_ptr_ref 的實現則是包含了一個 T* 的指針,構造 auto_ptr 時候直接從 auto_ptr_ref 中拷貝這個指針,因此這樣的實現可以上代碼編譯通過,運行也正確,不過不符合 C++ Standard 。

?

總結一下,危險的潛伏bug的隱式轉換應該被杜絕的,特別是 void * 的隱式轉換和構造函數的隱式轉換,因此建議是 :

  • 慎用 void * ,因為 void * 必須要求你知道轉換前的實現,因此更適合用在底層的、性能相關的內部實現。
  • 單一參數的構造函數應該注意是否允許隱式轉換,如果不需要,加上 explicit 。例如 STL 容器中 vector 接受從 int 的構造函數,用于預先申請空間,這樣的構造函數顯然不需要隱式轉換,因此加上了 explicit 。
  • 重載函數中,如果可能,就用更有明確意義的名字替代重載,因為隱式轉換也許會帶來一些意想不到的麻煩。
  • 避免隱式轉換不等于是多用顯示轉換。 Meyers Effective C++ 中提到,即使 C++ 風格的顯示轉換也應該盡量少用,最好是改進設計。
posted on 2006-07-25 00:37 Jerry Cat 閱讀(795) 評論(0)  編輯 收藏 引用

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理



<2008年7月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

常用鏈接

留言簿(7)

隨筆檔案

最新隨筆

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            蜜桃久久av一区| 亚洲国产一区在线| 亚洲综合丁香| 国产精品视频免费观看www| 亚洲午夜精品视频| 一本色道久久综合亚洲精品婷婷| 欧美二区在线播放| 在线视频一区观看| 亚洲图片自拍偷拍| 国产日韩一区二区| 久久最新视频| 欧美高清在线视频观看不卡| 亚洲视频欧美在线| 亚洲综合丁香| 亚洲第一福利视频| 日韩五码在线| 免费看av成人| 欧美激情精品久久久六区热门| 亚洲图片欧洲图片日韩av| 亚洲欧美日本国产有色| 精品91在线| aa级大片欧美三级| 国内精品久久国产| 亚洲精品中文字幕在线| 国产视频一区在线观看一区免费 | 国产一区二区三区观看| 牛牛国产精品| 欧美日韩午夜在线| 久久一区二区三区av| 欧美精品一区二区三区久久久竹菊| 亚洲香蕉网站| 久久免费视频这里只有精品| 一区二区日韩欧美| 久久激五月天综合精品| 亚洲天堂av在线免费| 久久九九热免费视频| 亚洲视频在线看| 久久久久国产精品厨房| 亚洲伊人色欲综合网| 美女视频一区免费观看| 欧美在线看片| 欧美日韩黄色一区二区| 欧美暴力喷水在线| 国产视频一区在线观看| 一本色道久久综合狠狠躁篇的优点| 极品尤物久久久av免费看| 亚洲一区二区三区精品在线观看 | 欧美日韩在线一区二区| 蜜桃精品久久久久久久免费影院| 国产精品爱久久久久久久| 亚洲黄色一区二区三区| 国产日韩欧美综合| 一区二区三区欧美在线观看| 日韩亚洲在线观看| 欧美国产日韩a欧美在线观看| 久久久国产一区二区| 国产欧美日韩高清| 一区二区精品| 亚洲视频电影图片偷拍一区| 欧美福利电影网| 欧美激情一区三区| 91久久国产综合久久91精品网站 | 欧美高清视频一区二区| 精品91视频| 久久成人精品| 久久亚洲欧美| 狠狠色综合色区| 欧美中文字幕精品| 久久久久久久综合| 黑丝一区二区三区| 久久久久综合| 欧美激情精品久久久久久免费印度| 精品电影在线观看| 免费视频一区二区三区在线观看| 另类激情亚洲| 91久久国产精品91久久性色| 美女视频黄 久久| 91久久黄色| 亚洲在线免费视频| 国产精品久在线观看| 午夜在线观看免费一区| 久久蜜桃精品| 亚洲七七久久综合桃花剧情介绍| 欧美极品一区| 在线视频免费在线观看一区二区| 午夜精品福利视频| 精品69视频一区二区三区| 久久亚洲春色中文字幕久久久| 欧美激情综合| 亚洲欧美日本精品| 韩国精品久久久999| 欧美国产欧美亚洲国产日韩mv天天看完整 | 国产尤物精品| 欧美成人精精品一区二区频| 亚洲看片网站| 欧美一区影院| 亚洲国产欧美日韩精品| 欧美午夜视频一区二区| 久久国产精品99国产| 亚洲大胆人体视频| 亚洲免费中文字幕| 亚洲福利视频网站| 国产精品久久久对白| 久久久999精品| 99成人在线| 美女脱光内衣内裤视频久久影院| 亚洲毛片一区| 国内外成人免费激情在线视频| 欧美大成色www永久网站婷| 亚洲一级在线观看| 亚洲大片免费看| 久久精品最新地址| 一本到12不卡视频在线dvd| 国产亚洲制服色| 欧美午夜视频一区二区| 美腿丝袜亚洲色图| 欧美一区二区三区久久精品茉莉花| 欧美激情第10页| 久久久午夜电影| 亚洲性感激情| 99国产精品国产精品久久| 精品动漫3d一区二区三区| 欧美性猛交xxxx免费看久久久| 蜜臀91精品一区二区三区| 欧美一区二区三区喷汁尤物| 亚洲靠逼com| 亚洲国产va精品久久久不卡综合| 久久www成人_看片免费不卡| 亚洲视频一区在线| 999在线观看精品免费不卡网站| 激情六月婷婷久久| 国产亚洲精久久久久久| 国产精品久久久久久久浪潮网站 | 欧美激情欧美狂野欧美精品| 久久成人精品一区二区三区| 亚洲欧美日韩在线一区| 亚洲午夜电影在线观看| 亚洲天堂网站在线观看视频| 一本久久综合| 99re6热在线精品视频播放速度| 亚洲黄色在线视频| 亚洲黄页视频免费观看| 91久久国产综合久久蜜月精品| 欧美国产另类| 亚洲国产精品成人久久综合一区| 欧美大色视频| 欧美高清视频在线播放| 亚洲电影第1页| 亚洲人成网站影音先锋播放| 最新中文字幕亚洲| 亚洲免费av片| 亚洲婷婷综合久久一本伊一区| 亚洲一区二区在线视频| 午夜精品成人在线| 久久精品日产第一区二区三区| 欧美一区亚洲一区| 久久一区中文字幕| 美国十次成人| 欧美日韩国产成人高清视频| 国产精品成人v| 国产欧亚日韩视频| 怡红院精品视频在线观看极品| 黑人中文字幕一区二区三区| 亚洲第一区在线观看| 日韩亚洲欧美高清| 欧美一区三区三区高中清蜜桃| 欧美日韩1区| 国产精品福利片| 国产一区深夜福利| 亚洲电影免费观看高清完整版| 亚洲国产精品高清久久久| 夜夜精品视频一区二区| 性做久久久久久免费观看欧美| 久久久国产精品一区二区三区| 欧美成人免费全部| 日韩午夜电影在线观看| 久久成人综合视频| 欧美激情综合在线| 国产欧美精品一区二区色综合 | 欧美性理论片在线观看片免费| 国产精品一二一区| 亚洲国产欧美久久| 亚洲欧美国内爽妇网| 久久综合色播五月| 夜夜嗨av一区二区三区中文字幕 | 亚洲精品中文字| 久久se精品一区精品二区| 欧美激情精品久久久久久变态| 国产精品视频久久一区| 亚洲精品国精品久久99热| 欧美一区二区性| 亚洲欧洲日产国产网站| 久久精品国产亚洲a| 欧美亚州一区二区三区 | 国产精品男女猛烈高潮激情| 在线观看中文字幕不卡| 欧美亚洲一级片| 亚洲欧洲一区二区天堂久久| 欧美在线三区| 国产精品一二三四|