2010-06-25 79 views
2

我想了解关于引用和右值的确切C++(前C++ 0x)行为。以下有效吗?
传递给const引用的C++ rvalue

void someFunc (const MyType & val) { 
    //do a lot of stuff 
    doSthWithValue (val); 
} 

MyType creatorFunc () { 
    return MyType ("some initialization value"); 
} 

int main() { 
    someFunc (creatorFunc()); 
    return 0; 
} 

我发现类似的代码库中的我试图修改。我发现Visual Studio 2005下的代码崩溃。
我了解上述情况的方式是:
creatorFunc按值返回,因此创建了一个临时的MyType对象obj1。 (并保留在堆栈上?) someFunc正在引用该临时对象,随着计算的进行,临时对象被覆盖/释放。
现在,令人难以置信的是,代码大多数情况下工作正常。更重要的是,通过一段简单的代码,我无法重现崩溃。
发生了什么/应该在这里发生?如果引用(val)是const或不是,那么问题很重要吗? creatorFunc返回的对象的生命周期是多少?

+0

你是不是指'someFunc(creatorFunc());'? – 2010-06-25 15:53:12

+0

当然,谢谢 – 2010-06-25 15:57:20

+0

你可能在某处引用了鼻子恶魔,他们正在奔跑。当你在代码中崩溃时,不应该定期崩溃,并且不能在简单代码中重新创建问题......通常这是感染从系统其他地方传播的鼻恶魔。 – 2010-06-25 16:16:54

回答

4

返回值的生命期是临时的,在C++中这意味着创建该类型的完整表达式,所以MyType的析构函数不应该在调用之后调用到someFunc返回。

我很好奇你的'被覆盖/释放'。当然在这个对象上调用delete是不行的;它生活在堆栈上并删除它可能会导致堆损坏。而且,覆盖/修改它也可能是不好的。你的例子使用了一个常量“C string”;在许多编译器中,像这样的值都存储在只读内存中,所以稍后尝试修改它可能会导致崩溃/访问冲突。 (但我不确定Visual C++是否执行此优化)。

传递const与可变引用之间的临时性有很大的区别。标准C++不允许创建对临时变量的可变引用,并且大多数编译器(包括GCC)都会拒绝它,尽管至少某些版本的Visual C++允许它。

如果您使用的是可变的引用传递给它,你想要写的是:

MyType t = creatorFunc(); 
    someFunc(t); 
+1

“完整的表达式”是表达式,直到第一个分号? – 2010-06-25 16:11:03

3

creatorFunc()创建的临时生命周期直到someFunc调用结束。有效地,下一个序列点(松散地,分号)。

someFunc正在采取这种临时对象的引用,并作为计算的进展被覆盖的临时对象/释放”

这听起来像someFunc正在做‘坏事’。你不应该覆盖或者释放一个由const&传递的对象

0

只能绑定一个临时的const引用。

0

是的,重要的是参考是常量。你不能将临时绑定到非const引用,所以代码不会编译。

除此之外,您的代码已定义良好,并且可按预期工作。

0

我曾经有过同样的问题,当我在SO上评论这样的话之前就曾经提过它。我觉得其他人有这个问题!

我还在使用VS 2005(SP1),也许一些编译器优化错误?

来自creatorFunc()的结果似乎没有保持活动的调用someFunc (creatorFunc());我唯一做的事情就是将其拆分为2行,从而删除临时变量。

1

正常情况下,临时对象(例如函数调用返回的对象)的生命周期延长到“封闭表达式”的末尾。然而,对参考文献的临时约束通常将其生命周期“提升”到参考文献的生命周期中。

因此临时被传递到someFunc()应该保持活着并且可以访问,直到someFunc()返回之后。但是,如果someFunc()(或其可能调用的任何内容,例如doSthWithValue())将指针或对val的引用(例如集合或某个其他对象)留存以供稍后使用,则该临时对象将不再活动并且尝试使用它可能会崩溃。这可能就是为什么你看到简单的代码不会导致临时崩溃,而更复杂的代码崩溃。

参见下列项目的更多细节:

return value (not a reference) from the function, bound to a const reference in the calling function; how is its lifetime extended to the scope of the calling function? C++ constant reference lifetime (container adaptor)

还要注意的是标准允许的临时被绑定只为const引用,但杰克劳埃德提到MSVC(有些版本之前VS 2003根据http://msdn.microsoft.com/en-us/library/cfbk5ddc.aspx)允许你将它们绑定到非const引用。但是,在一个快速测试中,我发现VS 2010的编译器仍然允许临时对象绑定到非const引用。

+0

与VS 2005相同,它允许将临时对象绑定到非const对象。 – 2010-06-28 17:48:36