2012-10-18 82 views
7

我有一个相当基本的C++的问题,可以考虑一个函数,需要一些输入参数,并创建一个std::string从类似下面的这些参数:C++返回临时对象混乱

std::string constructString(int some_parameter) { 

    std::stringstream ss; 

    // Construct a string (arbitrarily complex) 
    ss << "Some parameter is " << some_parameter << " right now"; 

    return ss.str(); //Am I not returning a temporary object here? 
} 

据我所知,当函数返回时,stringstream-object将超出范围,但是不会使构造的字符串无效?

如果我将返回类型更改为const char *并返回ss.str().c_str(),会发生什么情况?

像上面的代码似乎工作,但我怀疑这只是因为包含'临时'对象的内存还没有被别的东西覆盖时,我使用它?我不得不承认,如果有人能够解释这整个“临时对象” - 对我来说(或者只是指向正确的方向),我不得不承认,在这种情况下我会感到困惑。

THX提前

回答

10

你是返回一个临时对象,而是因为你的价值回报它,创建副本。如果您返回指向临时对象的指针或引用,那将是一个错误。

如果更改返回类型const char *并返回ss.str().c_str()你将返回指针的临时std::string一些缓冲的ss.str()返回,这将是糟糕的。

2

如您所见Stringstream::str()返回std::string对象。您在没有引用的情况下返回std::string,这意味着如果没有RVO(NRVO)优化拷贝构造函数将调用并创建有效的std::string对象。随着优化std::string将被移动没有复制构造函数。但是如果返回std::string&它将会崩溃,因为这个对象在函数返回后会被销毁。 const char *的效果相同,因为破坏这个指针后会指向错误的内存,这是危险的情况。

+0

调用constructString的函数不会拾取此副本后调用的析构函数吗?由于它是临时对象,因此我假定它的指针保存在堆栈上作为返回值。返回后会发生什么?如果没有新的对象所有者,它会被销毁吗?编译器如何知道该对象在返回后是否必须销毁? –

1

假设这是:T val = some_function(),当您从some_function返回一个值时,使用指定的拷贝构造函数或内置运算符将返回值的值复制到val。所以如果你返回一个int或者std::string就没有问题了,但是如果你返回一个指针指向一个将在函数结束时释放的内存,那么oops!你的指针将被指向一个无效的内存。例如,考虑这个:

const char* some_function() { 
    std::string res(...); 
    //... 
    return res.c_str(); 
} 

你是返回指针,将尽快释放的函数返回(因为res将被破坏,它会释放其内部的数据),所以你会得到的地址数据,但地址并不指向你所期望的!

+0

*“C++将返回值的值复制到val中”* - 甚至更多的是,它已将ss.str()返回的值复制到函数的返回值中,因为他按值返回。所以它甚至可以用'const T&val = some_function()',因为'some_function'返回值。 –

+1

'const T&val = some_function()'实际上可以很好地工作,因为C++通过值来复制每一件事,而'const T'实际上是一些不同的语义的'const T *',这里的问题是'const T&'指向一个位置在函数调用完成之后,这将失效! – BigBoss

+1

不,它不会,因为将const引用绑定到临时对象会延长临时对象的生命周期。这就是为什么'void foo(const std :: string&); foo(“test”);'完美无缺。不过,它不适用于指针(或非const引用)。这是一个小的差异,它使得引用确实不是指针语法糖的东西。 –