osstringstrream,stringstream str()返回临时变量问题

来源:互联网 发布:河北广电网络集团 编辑:程序博客网 时间:2024/06/05 16:25

我觉的要说清楚首先要从函数返回的临时变量的生命周期说起:

函数返回的临时变量是放在堆栈上的,所以返回来后如果你没有调用其他的函数,那么这个临时变量在依然保存在堆栈中,是可以被引用的。

因为这时堆栈并没有被破坏。但是一旦调用其他函数后堆栈被破坏了,那个返回值就没有用了。

例如:一个函数返回类型是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内部有一个指针,

(可以通过sizeofstring)返回值是4知道,当然我是在CENTOS 4.4上实验的,不同的编译器可能不同),

另外,stringCOW模式。

 

如果要知道真正的上面两行代码为何正常工作,还要从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上的结果,如果不同的系统或者不同的编译器,结果可能不能。