临时对象的生存期

来自于CSDN上的一个帖子,题目很吓人, 发现了VS 2005的一个重量级Bug!

还是直接给出代码:

#include <iostream>
#include <string>

using
namespace std;

int
main()
{
    const
char *p = string( "hello" ).c_str();
    cout << p << endl;
    return
0 ;
}

想想输出结果是什么?

这时VS2005和g++的结果就不一样了。VS2005上什么都不输出,而g++ 3.4上则输出了似乎非常合理的结果:hello,符合很多人的预期。不过查了标准以后,还是把票投给VS2005。

首先, string( "hello" )产生了一个temporary object,或者说临时对象。C++标准对临时对象的生存期(life time)有明确的规定,可见标准12.2节第3-5条。第3条讨论了临时对象的析构时间:

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节。整个对p的初始化构成了一个full-expression。在下结论之前,还要先看看第4、5条,分别讨论了两个例外情形,一个是将临时对象作为初始化子,例如 string s = string( "hello" );第二是将一个引用变量绑定到这个临时对象上,例如 const string &s = string( "hello" ),总而言之,在这两种情形中可以通过一个名字来存取这个对象,此对象的生存期就延长到变量名的作用域结束。除此之外,都按照第3条处理。

有了这些准备,拿前面给的例子往里套就明白了:这里没有出现4、5所指出的例外,因此第3条的原则适用。而不管full-expression如何,可以确定的是在p被初始化之后临时对象 string( "hello" )的析构函数就应该被调用。在VS2005中进行调试,可以发现string析构函数调用的时间就在p被初始化之后,语句 cout << p << endl执行之前。手头没有方便的工具来调试g++编译出来的程序(不太会用gdb调试C++程序,特别涉及到STL)。至于之后p指向的内存到底如何,则和具体的string实现相关了。这样分析下来,VS2005的结果还是比较不错的,而g++的结果则容易让人产生误解。

Update:察看g++编译出来的汇编代码,发现g++同样在表达式求值后析构了临时对象,只不过由于实现上的原因,p指向的内容还没有清空。

你可能感兴趣的:(临时对象的生存期)