延长临时工的寿命
允许这样做的设计原理是什么
What is the design rationale behind allowing this
const Foo& a = function_returning_Foo_by_value();
但不是这个
Foo& a = function_returning_Foo_by_value();
?
第二行可能会出错(第一行不会出错)?
What could possible go wrong in the second line (which would not already go wrong in the first line)?
推荐答案
我会回答你的问题......反过来.
I'll answer your question... the other way around.
为什么他们允许 Foo const&foo = fooByValue();
以 ?
Why did they allowed Foo const& foo = fooByValue();
to begin with ?
它让生活(在某种程度上)更轻松,但会在各处引入潜在的未定义行为.
It makes life (somewhat) easier, but introduces potential undefined behavior all over the place.
Foo const& fooByReference()
{
return fooByValue(); // error: returning a reference to a temporary
}
这显然是错误的,编译器确实会尽职尽责地报告.根据 Tomalak 的评论:标准没有强制要求,但好的编译器应该报告它.Clang、gcc 和 MSVC 都可以.我认为 Comeau 和 icc 也会.
This is obviously wrong, and indeed the compiler will dutifully report it. As per Tomalak's comment: it is not mandated by the standard, but good compilers should report it. Clang, gcc and MSVC do. I think that Comeau and icc would too.
Foo const& fooByIndirectReference()
{
Foo const& foo = fooByValue(); // OK, you're allowed to bind a temporary
return foo; // Generally accepted
}
这是错误的,但更微妙.问题是临时变量的生命周期与 foo
的生命周期绑定,它在函数结束时超出范围.foo
的副本被传递给调用者,这个副本指向以太.
This is wrong, but is more subtle. The problem is that the lifetime of the temporary is bound to the lifetime of foo
, which goes out of scope at the end of the function. A copy of foo
is passed to the caller, and this copy points into the ether.
我在 Clang 上提出了错误,Argyris 能够诊断出这个案例(真的很赞:p).
I raised the bug on Clang, and Argyris was able to diagnose this case (kudos really :p).
Foo const& fooForwarder(Foo const&); // out of line implementation which forwards
// the argument
Foo const& fooByVeryIndirectReference()
{
return fooForwarder(fooByValue());
}
由 fooByValue
创建的临时对象绑定到 fooForwarder
参数的生命周期,它尽职尽责地提供一个副本(引用的),副本返回给调用者,即使它现在指向以太.
The temporary created by fooByValue
is bound to the lifetime of the argument of fooForwarder
, which dutifully provide a copy (of the reference), copy that is returned to the caller, even though it now points into the ether.
这里的问题是 fooForwarder
的实现完全符合标准,但它在调用者中创建了未定义的行为.
The issue here is that fooForwarder
's implementation is perfectly fine wrt the standard, and yet it creates undefined behavior in its caller.
尽管如此,令人生畏的事实是,要对此进行诊断需要了解 fooForwarder
的实现,而这对于编译器来说是遥不可及的.
The daunting fact though, is that diagnosing this requires knowing about the implementation of fooForwarder
, which is out of reach for the compiler.
我能理解的唯一解决方案(除了 WPA)是运行时解决方案:每当临时对象绑定到引用时,您需要确保返回的引用不共享相同的地址......然后是什么?断言
?引发异常?而且由于它只是一个运行时解决方案,显然不能令人满意.
The only solution I can fathom (apart from WPA) is a runtime solution: whenever a temporary is bounded to a reference, then you need to make sure that the returned reference does not share the same address... and then what ? assert
? raise an exception ? And since it's only a runtime solution, it is clearly not satisfactory.
将临时对象绑定到引用的想法很脆弱.
相关文章