Posted on 2006-09-04 23:23
chenger 閱讀(1373)
評論(13) 編輯 收藏 引用 所屬分類:
Programming Stuff
來自于CSDN上的一個帖子,題目很嚇人,
發(fā)現(xiàn)了VS 2005的一個重量級Bug!還是直接給出代碼:
#include <iostream>
#include <string>
using namespace std;
int main()
{
??? const char *p = string("hello").c_str();
??? cout << p << endl;
??? return 0;
}想想輸出結(jié)果是什么?
這時VS2005和g++的結(jié)果就不一樣了。VS2005上什么都不輸出,而g++ 3.4上則輸出了似乎非常合理的結(jié)果:hello,符合很多人的預期。不過查了標準以后,還是把票投給VS2005。
首先,
string("hello")產(chǎn)生了一個temporary object,或者說臨時對象。C++標準對臨時對象的生存期(life time)有明確的規(guī)定,可見標準12.2節(jié)第3-5條。第3條討論了臨時對象的析構(gòu)時間:
3. ... Temporary objects are destroyed as the last step in evaluating
the full-expression (1.9) that (lexically) contains the point where
they were created. This is true even if that evaluation ends in
throwing an exception.
這又涉及到full-expression的定義了,參見1.9節(jié)。整個對p的初始化構(gòu)成了一個full-expression。在下結(jié)論之前,還要先看看第4、5條,分別討論了兩個例外情形,一個是將臨時對象作為初始化子,例如
string s = string("hello");第二是將一個引用變量綁定到這個臨時對象上,例如
const string &s = string("hello"),總而言之,在這兩種情形中可以通過一個名字來存取這個對象,此對象的生存期就延長到變量名的作用域結(jié)束。除此之外,都按照第3條處理。
有了這些準備,拿前面給的例子往里套就明白了:這里沒有出現(xiàn)4、5所指出的例外,因此第3條的原則適用。而不管full-expression如何,可以確定的是在p被初始化之后臨時對象
string("hello")的析構(gòu)函數(shù)就應該被調(diào)用。在VS2005中進行調(diào)試,可以發(fā)現(xiàn)string析構(gòu)函數(shù)調(diào)用的時間就在p被初始化之后,語句
cout << p << endl執(zhí)行之前。手頭沒有方便的工具來調(diào)試g++編譯出來的程序(不太會用gdb調(diào)試C++程序,特別涉及到STL)。至于之后p指向的內(nèi)存到底如何,則和具體的string實現(xiàn)相關(guān)了。這樣分析下來,VS2005的結(jié)果還是比較不錯的,而g++的結(jié)果則容易讓人產(chǎn)生誤解。
Update:察看g++編譯出來的匯編代碼,發(fā)現(xiàn)g++同樣在表達式求值后析構(gòu)了臨時對象,只不過由于實現(xiàn)上的原因,p指向的內(nèi)容還沒有清空。