一個關於臨時物件的BUG(下) (轉)

worldblog發表於2007-08-14
一個關於臨時物件的BUG(下) (轉)[@more@]

 這一切看起來都非常美妙,但是如果是下面這個例子,會發生什麼情況呢?:namespace prefix = o ns = "urn:schemas--com::office" />

MyClass &mc = foo();

現在將不是將臨時複製到新的物件上面,我僅僅是將它賦值給一個引用,(請注意,這和最開始那個例子有一點區別,在第一個例子裡面,我將一個區域性變數的引用做為了返回值,而在這個例子裡,我是將一個函式返回的臨時變數的引用賦值給一個變數)。那麼,現在將會發生什麼情況呢?臨時物件將在什麼時候被銷燬呢?如果它還是在的執行結束的時候被銷燬,就如同上面那個例子一樣,這段程式碼將因為一個指向不存在的物件的應用而徹底完蛋。但是,請注意,C++標準同意對這種情況提出一種不同尋常的解決辦法:如果一個臨時物件被賦值給一個引用,這個臨時物件在這個引用的生命週期中將不能被銷燬。換句話說,不同於返回一個區域性變數的引用,將一個引用繫結到一個臨時物件上是完全合法的,任何時候使用這個引用,這個物件都應該是有效的。

The

我猜我只能說僅僅當恰當的實現了C++標準,這個引用才可能是有效的。Eugene Gershnik將Listing 2所列的程式碼傳送給了我,它有一個叫foo的函式,返回了一個std::vector型別的臨時物件,並且這個物件被賦值給了一個引用,當這段在VC7的Release下編譯並執行時並沒有問題,但是當它在Debug模式下執行時,我得到了這樣一個錯誤:

The instruction at 0x004121b5referenced memory at 0x00000000.The memory could not be read.

Listing 2

Assigning a reference to a temporary

// Problem with reference bound to temporary

// The function foo returns a temporary object

// of type std::vector, which is then bound

// to a reference of type const std::vector&.

// When the expression "int m[80] = {0};" is

// executed,

// the reference bar no longer seems to be valid,

// and the program will crash in the call to

// printf.

// Removing the line "int m[80] = {0};" eliminates

// the problem.

//

// Compile with VC7, with the "Program Database

// for Edit and Continue" debug option.

#include

#include

std::vector foo()

{

std::vector ret(20);

return ret;

}

int main()

{

const std::vector &bar = foo();

int m[80]={0};

std::printf("%d ", bar[0]);

return 0;

}

開始的時候我猜想由於Release版本對“int m[80]= {0};”這一行的造成了這種結果,因為這行程式碼確實什麼也沒有做,我認為這種最佳化消除了在Release下的錯誤。但是當我將程式碼發給Microsoft,並徵求他們的意見的時候,Jeff Peil給我回了信,並指出了真正的原因所在:

  這個問題是由於編輯-繼續支援(edit-and-continue debugging support

  的功能而造成的。這個錯誤將在即將釋放的下一版的Visual C++中得到修

  正,你可以透過將編輯-繼續除錯支援從編譯選項中去掉而避免這個錯誤

  發生(編譯時仍然會產生除錯資訊,你需要做的僅僅是將/ZI選項替換成

  /Zi選項)。當然,另外一個解決辦法就是不將引用繫結到臨時物件上去,

  這樣你可以繼續使用編輯-繼續除錯支援功能,就像下面的程式碼那樣:

int main()

{

std::vector bar;

std::s(bar,foo());

int m[80]={0};

std::printf(%d , bar[0]);

return 0;

  —Jeff Peil

雖然上有一點點損失,但Jeff的程式碼工作的很好。這兩個Vector的內容粗看起來是一個代價昂貴的操作,但實際上所有的交換工作就是交換兩個陣列中很少的內部變數,這其中並不涉及到緩衝區的複製,因此交換將在常量時間內完成。

當然如果你想簡單的解決這個問題,可以將表示式“int m[80]= {0};”移動到宣告變數bar之前。因為它們之間不存在什麼倚賴關係,先宣告任何一個都是沒有關係的。

   (完)


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

相關文章