對話#25:Getting to the Point (轉)
“啊!”:namespace prefix = o ns = "urn:schemas--com::office" />
這一個小時內我第七次受挫後的大叫。 溫迪明顯不勝其擾了。”瞧瞧,朋友,安靜一下,好吧?”她的飄過隔間。我覺得她的反應比以前好多了。
我以前就和auto_ptrs搏鬥過了。在為Guru幹活的最初幾天內,我已經領教過auto_ptrs的價值了-以及它那不顯眼的陷阱[1]. 我已經被auto_ptr那奇怪的所有權問題扎過一次了。auto_ptr使用偽裝為複製操作的移交操作。想像一下這種情況: 你在操作一個影印機,放上你的表格,然後按 “複製”按鈕。過了一會兒,影印機給你副本-然後將原件送入碎紙器。這就是auto_ptr的複製和賦值操作乾的好事。
無論如何,我現在已經更聰明和更富有了,可仍然正陷入在auto_ptr的形形色色的限制之中。比如說,auto_ptr不能用來包容指向陣列的指標。我玩弄了一個ing的技巧來繞開它,透過使用顯式的陣列delete:
auto_ptr
//...
delete [] autoArray.release;()
但立刻就後悔了。我可以預見到這個 “面目可憎的東西”(Guru會也會這麼稱呼它) 的許多危險。最重要的是,嗯,auto_ptr的賣點就是擁有和銷燬;手工這麼做完全打破了使用它的本意。
因此,我決定改用一個vector來擁有陣列。它比我所需要的還更強勁一些,因為我不需要動態更改vector的大小,而它提供了此功能。 我實際上想要是一個能自動處理指標和記憶體管理的靈巧指標,並且可以用來處理陣列。
“使用Boost庫, 天行者,”我聽到身後Guru的聲音。
“是不是‘使用大場,天行者’?” 我側肩答道。 “而且,不要叫我天行者。”
“Boost是能量的源泉,”Guru繼續於她的電影臺詞之中。
我今天沒心情,於是我打斷了她。”嗯,我們能今天不用演戲嗎?鮑伯在倫敦的辦公室裡,也沒有新員神情反常。”
她來到附近,我看見了她的微笑和聳肩。”哦,我僅僅感到無聊,”她嘆了口氣。”你看過Boost庫中的靈巧指標了嗎?”
“嗯,”我吞吞吐吐的,”我還沒空仔細去看Boost庫。它怎麼實現靈巧指標的?”
“共有五種靈巧指標,”Guru一邊坐下一邊說著。”兩個處理指標的單所有權,兩個處理共享所有權。”
“共享所有權?哦,類似於帶引用計數的類?”
“完全正確。靈巧指標是成對的,一個處理指向單一物體的指標,另一個處理指向陣列的指標。”在說的時候,她在白板上寫下:ped_ptr,scoped_array,shared_ptr和 shared_array。
“只有四個,你前面說有五個?”我問。
“剩下的一個叫weak_ptr。它是shared_ptr的非擁有關係的觀察者。我隨後講它。 scoped_*形靈巧指標在它們離開生存範圍時,自動析構所指向的。一個提議用途是實現Pimpl慣用法-指向實現的指標,”在我發問前,她急忙加了一句。
“如此說來...他們象auto_ptr,對吧?”
“不十分象。scoped_ptr和scoped_array不可複製。”
“不可複製?那麼,如果我將一個指標作為類的成員-”我邊說邊在白板上潦草地寫著:
class T
{
scoped_ptr
...
“-我如何實現複製和賦值?”
“和auto_ptr一樣,”Guru邊答邊寫:
T( const T& other )
: p(new TImpl(*other.p)
{
}
T& operator=( const T& other )
{
scoped_ptr
p.s;(tmp)
}
“Ooookay,”我懶洋洋地說著,裝作我已經懂了。“ 於是,當我使用scoped_ptr的時候, 我必須同樣完成使用auto_ptr時所必須做的所有工作,對吧?那麼為什麼不就使用auto_ptr?”
“因為使用auto_ptr時能編譯,但是做錯事, 因為自動生成的。 使用 scoped_ptr 使得極難忽略複製語義,因為如果你使用編輯器自動生成的版本時,編輯器將會拒絕編譯這個類。同樣,scoped_ptr不能夠在一個不完全的型別上被使用。”我給予了Guru我擅長的車前燈前的鹿的目光。 她嘆了口氣。“考慮這種情況,”她邊說邊在白板上寫:
class Simple;
Simple * CreateSimple();
void f()
{
auto_ptr
scoped_ptr
//...
}
“在函式體中,Simple是一個不完全的型別。如果它的解構函式是有行為的,那麼透過auto_ptr或scoped_ptr銷燬它,其結果為未定義。一些在你例項化auto_ptr時將會警告你這一點,但不是所有編譯器都會這麼做。相對的,scoped_ptr為確保語義正確而做了些小動作以造成編譯錯誤,如果是在例項化一個不完全型別的話。”
“哦,是的,當然,” 我來勁了,以顯示我理解了。 “因此我們應該始終使用scoped_ptr來代替auto_ptr,對吧?”
“錯,抱歉,” 她失望地說道。“auto_ptr仍然有它的用處。不像auto_ptr,scoped_ptr 沒有release()成員-它不能夠放棄指標的所有權。 因為這個,以及因為scoped_ptr不能夠被複制,當scoped_ptr離開生存範圍時,它所管理的指標總是被delete。這使得scoped_ptr不適用於需要傳遞所有權的地方,比如廠。”
“使用scoped_ptr向其他員表明你的意圖。它告訴其他人,‘這個指標不應該在當前範圍外被複制’。正相反,auto_ptr允許從產生指標的程式碼空間向外傳遞所有權,但是它維持對指標的控制除非所有權的傳遞是完全地。 這當然對寫異常的程式碼有重要意義。”
“啊,好,我明白了,”我嘟囔著。“ 你提到的另一種靈巧指標是怎麼回事?”
“scoped_array的行為和scoped_ptr相同,除了它處理是物件陣列而不是單個物件。 scoped_array 提供了稍有差別的訪問函式。它沒有operator*或operator->,但它有operator[]。我相信,”她總結道,“你需要是一個 scoped_array。”
“也許吧,”我答道,”但是我認為在作決定之前我應該多瞭解些shared_*形的靈巧指標。”
“非常明智,我的徒……弟,抱歉,叫習慣了。”Guru歉意地笑了一下。“是的, 熟悉各個選擇之後再作決定是個好習慣。”
她指著白板上的shared_ptr 和 shared_array說道:“shared_*形的靈巧指標是非常有用的工具。 他們是引用計數型的指標,能夠區分出所有者和觀察者。舉例來說, 使用上面的class T:”
void sharing()
{
shared_ptr
shared_ptr
//...
}
“兩個shared_ptr物件指向相同的T物件。引用計數現在是2。既然shared_ptr是引用計數的,物件一直不被銷燬直到最後一個shared_ptr離開生存範圍-此時引用計數降為0。shared_*的靈巧指標有相當的柔性,你可以使用它們包容指向不完全型別的指標。”
“我想你說過的,這很糟吧?”
“是很糟,如果你不小心的話。 shared_*的靈巧指標可以用一個指向不完全型別的指標來例項化,但必須要指明一個函式或函式子供銷燬被擁有物件時。比如說,我們修改了上面的f函式:”
void DestroySimple( Simple* );
void f()
{
shared_ptr
shared_ptr
}
“第一個shared_ptr失敗了, 因為Simple是一個不完全型別。第二個成功了,因為你明確地告訴了 shared_ptr 該如何銷燬這個指標。
“因為 shared_ 指標被設計可被複製,它們完全適用於標準容器, 包括associative 容器。並且,在那些必須強制型別轉換的特別場合上,可以定義特別的型別轉換操作以生成新的shared_*形的靈巧指標。 例如,如果我們有一個類Base以及公有繼承而來的Derived,和一個無關類,那麼你將遇到:”
void g()
{
shared_ptr
shared_ptr
shared_dynamic_cast
shared_ptr
shared_dynamic_cast
try
{
shared_ptr
shared_polymorphic_cast
}
catch( bad_cast)
{
//...
}
}
“同樣還存在著一個shared_static_cast,供那些特別場合使用,”Guru總結道。
我對這個函式研究了一會兒。“好吧,讓我試試是否能推算出將發生什麼。第一個shared_dynamic_cast在靈巧指標上了一個dynamic_cast,返回一個新的靈巧指標。 假如dynamic_cast失敗了怎麼辦-在引用計數上將發生什麼?”
Guru滿意地點點頭。“在那種情況下,原始的計數不被影響,而且新的hared_ptr包容的是一個NULL指標。正如你從try/catch語句推測的,shared_polymorphic_cast將試圖在被容納的指標上執行dynamic_cast。 如果轉換失敗,它將丟擲bad_cast異常。”
“哇,”我讚歎道,“這個類可真完備。看起來很不錯。”
“的確,”Guru同意。 “但還有些事情是必須要知道的。引用計算過於簡單而不能檢測任何形式的迴圈引用。同樣,shared_ptr也沒有實現任何形式的寫時複製(copy-on-write),因此用它來實現Pimpl慣用法時必須仔細衡量。”
我深思熟慮後確定我喜歡它。“嗨,”我追問道,我還記著呢,“你提到過的weak_ptr是怎麼回事?”
“啊,是的。weak_ptr與shared_ptrs聯合使用。weak_ptr是觀察者,不影響共享物件的引用計數。weak_ptr的主要目的是允許shared_ptr參與迴圈依賴-A引用B,B反過來又引用A。我喜歡將它想象成俱樂部中的準會員-它沒有投票權,但是能參加俱樂部的會議。”
“Hmmm……” 我仔細想了一下。“因為 weak_ptr不影響引用計數,如果俱樂部解散了怎麼辦-也就是說,最後一個shared_ptr離開了生存範圍-而此時 weak_ptr正在使用共享物件?”
“在那情況下,weak_ptr維護的指標被設定為NULL。而對於NULL,不能進行任何dereferencing操作,例如operator*、operator->、或operator[],在dereferencing指標前應該進行NULL檢查。於是,正如dereferencing內建指標前必須進行NULL檢查,你也一定要檢查靈巧指標是否為NULL。這個限制適用於Boost庫中的所有靈巧指標。”
“天那,要記太多的東西了,”我一邊說一邊盯著潦草地寫在白板上的東西。
“別擔心,”Guru微笑著站起離開了。“我會e給你Boost庫的URL,以及練習和示範各種不同指標的一個小程式。”她當然說到做到,幾分鐘內我收到了她的。 我讀到這句時立即就閉上了眼睛:
“我的徒弟,如前所說,這是Boost庫中的說明文件:
[感謝]
Thanks to Peter Dimov and Bjorn Karlsson for providing valuable comments and updates.
[註釋]
[1] Jim Hyslop and Herb Sutter. “Conversations #1,” C++ Report, April 2000.
[2] The most recent version of the library and documentation can also be obtained via anonymous checkout from the Forge project. Detailed instructions can be found at: /projects/boost/"><.
[3] The sample code can be ed from the CUJ site: ://ftp.cuj.com/pub/2002/2007/hyslop.zip">hyslop.zip.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991792/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Getting Listeners from JavaBeansTM (轉)JavaBean
- Getting Testing PKGBUILDs(轉)UI
- 網友對sars病毒事件的對話(轉)事件
- 關於openssl應用的對話 (轉)
- Linux kernel 'getting buggier'[英文](轉)Linux
- 對話方塊中對成批控制元件的操作 (轉)控制元件
- Borland與Microsoft關於Delphi的對話 (轉)ROS
- 浮點型(Floating-Point Types)(轉)
- RESTORE POINTREST
- 進一步學習對話方塊(轉)
- 對話#28:Contracts, Promises, and Mere Semantics (轉)Promise
- 對話方塊背景色的設定 (轉)
- Beaglebone - Getting Started
- Performing Tablespace Point-in-Time Recovery with Recovery Manager(轉)ORM
- InstallShield自定義對話方塊模板程式碼(轉)
- 重新顯示 Windows 98 歡迎對話方塊(轉)Windows
- InstallShield自定義對話方塊淺談(三) (轉)
- InstallShield自定義對話方塊淺談(四) (轉)
- InstallShield自定義對話方塊淺談(五) (轉)
- cocos2d anchor point 錨點解析(轉)
- getting started with transformjsORMJS
- Windows HLK Getting StartedWindows
- JavaScript some pointJavaScript
- 利用非對話語料來豐富對話生成模型模型
- 對話即資料流:智慧對話的新方法
- study critical point and saddle point using Hessian Matrix
- VC實現對話方塊上資訊的顯示 (轉)
- IE中非模式對話方塊(showModelessDialog)應用 (轉)模式
- 路由器配置基礎--設定對話過程 (轉)路由器
- JavaScript視窗功能指南之建立對話方塊 (轉)JavaScript
- 《最後期限》:人怎樣對軟體工程說話 (轉)軟體工程
- 資料夾選擇對話方塊 JS實現(轉)JS
- 轉用Linux的25條理由(轉)Linux
- 對話論文總結
- Hive Getting Started補充Hive
- ElasticSearch 2 (1) - Getting StartElasticsearch
- Getting More Information about PartitionsORM
- IBM對話設計指南:對話聊天框設計挑戰IBM