Herb Sutter的對話#30:It's an Object-ful Lifetime (轉)

worldblog發表於2008-01-06
Herb Sutter的對話#30:It's an Object-ful Lifetime (轉)[@more@]

-ful Lifetime(WQ譯):namespace prefix = o ns = "urn:schemas--com::office" />


那是在假日的前幾天。難得一次, 沒有截止期限的壓迫—我所從事的專案都已經按時完成了。

我經常在原始碼庫中閒逛以作為消遣。當研究其他員的程式碼時,我時常學到新的技巧—以及應該避免的技巧。 我偶然發現了一個有趣的東西,它被濃縮在下面的小程式中:

class T

{

public:

 T & ref(){ return *this;}

};

 

void f(T &);

 

int main()

{

 f(T().ref());

}

起先 ,我沒了解ref()的意圖,因此我移除了對它的—我預料它應該能夠工作:

int main()

{

  f(T());

}

然而,當我編譯它時,提示有一個錯誤一在臨時上繫結了一個非const的引用。 我拍了一下腦袋—這當然是不允許的!我回想起Guru的講解,就在我第一次碰到這個問題的時候。

" 此禁令的一個理由是要避免一些微妙的,"她曾經說過。"我的孩子 , 考慮下列情況:"

class U

{

//...whatever...

};

 

void takesAndModifiesU( U & u)

{

 // performs actions that modify the state of u

}

 

class V

{

public:

 operator U();

};

 

void g()

{

 V v;

 //...

 takesAndModifiesU;( v)

 //...

}

"如果繫結被允許,編譯器會呼叫型別轉換操作,構造一個臨時的U物件。然後這個無名的臨時物件將被傳給takesAndModifiesU並被修改,然後在函式呼叫完成後被丟棄。最初的物件v,根本就沒有被動過-這將給寫這個函式的人以極大的困擾。"

但是,我還是被困擾了。我不明白最初的f(T().ref());語句怎麼可以編譯的—它還是在一個臨時物件上繫結了一個非const的引用啊。

"你不能侷限在不變性上,我的孩子,"Guru震驚了我—來自於真實世界的,而不是記憶中的。"轉而想一下lvalue和rvalue。神聖的標準告訴我們T()形式的一個顯式型別轉換產生一個rvalue。 rvalue只能繫結到一個const的引用,而lvalue沒有這個限制。另一方面,返回引用的函式,其結果是得到一個lvalue[1]. 因此編譯器能將非const的引用繫結在ref()的結果上。"

"於是,只要我呼叫一個返回引用的函式就沒問題了,"我答道。 " 嗨—賦值運算子返回引用,因此我可以寫 f(T() = T());。多妙!"我來勁了。 "我能想出這個技巧有很多用途"。

"小心,我的孩子。 如此不尋常的技巧是危險的,不應該輕易使用。 的確,我認為至少有一問題,關於物件生命期的,會導致未定義行為。"

" 那個是..." 我催促道。

" 先自己想,午飯之後吧,"Guru緩緩答道。在遠處,我看見一些同事已經準備去吃部門的假日聚餐了。我抓起外套,加入了他們,前往附近的一家飯店。

不知何故,我們實際上設法避免在吃飯時討論購物。 討論集中在我們喜愛的假日電影上,comparing the various remakes of Miracle on 34th Street, and whether Alistair Sim or Patrick Stewart made a better Scrooge。 (My vote was for Stewart。) Bob surprised me, though — I figured his favorite character would be the Grinch, but instead he waxed poetic on It's A Wonderful Life.(WQ注:Sorry,由於和技術無關,而又實在譯不好,所以沒譯。)

當我們吃完飯回來,我感覺很好。我在桌前坐下並開始沉思Guru所指的是什麼。 最後,當我努力保持眼睛睜開時,我明白了:

class U

{

 T & t_;

public:

 U( T & t) : t_( t ) {}

};

 

{//... some block pe ...

 U u( (T() = T()) );

 //...

}

一旦u物件完成構造,臨時物件的生命期就結束了,而u物件會帶著一個懸掛引用被留了下來。

就好象T物件從來沒有存在過,我陷入沉思中。

"好的,George,"我聽到了Guru的聲音,"你已經得到了你的願望。你從來就沒有出生過。"

"嗯? George是誰?"我轉向Guru。

"當然是你,"Guru答道。我一看到她,就認識到我正在做夢—那種你明知道是夢,但走到哪裡都跟著你的夢。"你是George Bailey。 你構造的物件從來沒有存在過。我的工作就是向你說明當涉及未定義行為時會發生什麼。"

在遠處,我看到一個條幅:"歡迎來到Bobville。"

"Bobville?" 我問,畏懼於這個名字。

"城鎮是由你的死對頭Bob控制,"Guru說道。 "他也是銀行的擁有者 , 和開發部的頭兒。讓我們沿主要街道散步一下。"

當我們向前走的時候,我看見了不能言狀的驚駭—沒有分隔的整塊程式碼,被命名為i和j的變數,和"NULL指標的反引用於此"的商業廣告牌。在一個街道拐角上,我看見了一些程式設計師正毫無愧色地複製-貼上程式碼。

我看見Kerry駕駛正駕駛著一輛出租汽車。我示意他停下來。

"把我帶離這裡,Kerry," 我在鑽入車廂時喊道。 "把我帶回辦公室,那個我們寫出理性程式碼的地方"。

"Kerry?我的名字是Ernie(搖獎機)。 我不懂寫程式碼; 我只是開計程車的。"我們從Wendy旁駛過,她穿著警服。Kerry揮手向她示意。知道它是一個夢,而我沒有被設定為注意他的行動,我忽略了他。

我們在一棟廢棄的辦公大樓前停下。 我跳出車跑進去。我找到了一塊白板,它上面有一些不爽的程式碼,於是重寫了它:

{//... some block scope ...

 T tmp;

 U u( tmp );

}

就在我放下書寫筆時,我被驚醒了。

"哇 !" 我自言自語著,一邊去餐廳拿我能找到的最濃的咖啡。

注:

[1] ISO/IEC 14882:1998(E), "International Standard, Programming Languages — C++", clauses 5.2.3, 8.5.3, and 3.10 respectively.


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-996672/,如需轉載,請註明出處,否則將追究法律責任。

相關文章