我觉的要说清楚首先要从函数返回的临时变量的生命周期说起:
函数返回的临时变量是放在堆栈上的,所以返回来后如果你没有调用其他的函数,那么这个临时变量在依然保存在堆栈中,是可以被引用的。
因为这时堆栈并没有被破坏。但是一旦调用其他函数后堆栈被破坏了,那个返回值就没有用了。
例如:一个函数返回类型是string
string func()
{
String a;
…
return a;
}
使用如下:
string b;
b = func();
其过程如下:
1) 当func返回时,会产生一个临时变量
2) 将要返回的值a拷贝到临时变量中,因为一旦func执行完毕a就会被析构。
3)变量b再调用赋值操作将临时变量的值赋给b
4)临时变量析构。
再让我们看看osstringstream 的str的源代码,如下:
typedef basic_string<char_type, _Traits, _Alloc> __string_type;
__string_type str() const
{
if (this->pptr())
{
// The current egptr() may not be the actual string end.
if (this->pptr() > this->egptr())
return __string_type(this->pbase(), this->pptr());
else
return __string_type(this->pbase(), this->egptr());
}
else
return _M_string;
}
从这段代码中,我们可以知道它确实返回的是一个临时的变量,类型是string。
再根据邮件中的例子:
const char* pA = sA.str().c_str();
printf("stringstream2:%s/n", pA);
按理说,调用printf时,由于临时变量已经被析构了,应该出错。可是编写程序测试,并没有出错,而且内容还被打印出来了。为什么呢?
建议,先看看 <Effective C++ > 条款15:小心string实现的多样性
看过之后,可以知道,string的实现方式,string内部有一个指针,
(可以通过sizeof(string)返回值是4知道,当然我是在CENTOS 4.4上实验的,不同的编译器可能不同),
另外,string是COW模式。
如果要知道真正的上面两行代码为何正常工作,还要从STL的内存管理说起,简单概述如下:
STL有一个内存池,小于128字节的都从内存池中分配,大于128字节的从系统分配,而且,一旦STL分配内存,将不再释放,放入内存池中,以备后用。
const char* pA = sA.str().c_str();
printf("stringstream2:%s/n", pA);
这两行代码,虽然返回的临时的string对象析构了,但是,指针还没有被用作它用,所以,它的内容尚在,可以被正确打印出来。
但是如果稍微修改以下:
假设sa的内容是:” CStringTester::testConstructor”
const char* pA = sA.str().c_str();
string strTempObj(“Hello, How are you!”);
printf("stringstream2:%s/n", pA);
你会惊奇的发现,打印的是: stringstream2:Hello, How are you!
为什么打印的内容变了?? 原因是两个字符串的长度差不多,所以,他们使用的是同一个内存池中的内存,临时变量释放的内存被新的变量使用了,所以打印的内容变了。
代码再修改为;
const char* pA = sA.str().c_str();
string strTempObj(“Hello, How are you! I am fine, thank you. It should be long enough !!”);
printf("stringstream2:%s/n", pA);
再看打印的值,这次打印的值和原来一样了。
这是因为,这次strTempObj的长度比较长,它需要使用更长的内存池中的内存,没有使用临时变量释放的内存,所以,这次内存的内容没有被修改。
以上内容在CENTOS4.4 GCC3.4.6上的结果,如果不同的系统或者不同的编译器,结果可能不能。