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