使用clang-3.5将以下代码编译为c++ 11标准时:
const String& XMLAttributes::getValueAsString(const String& attrName, const String& def) const
{
return (exists(attrName)) ? getValue(attrName) : def;
}
我得到以下警告:
warning:
returning reference to local temporary object [-Wreturn-stack-address]
return (exists(attrName)) ? getValue(attrName) : def;
^~~
note:
binding reference variable 'def' here
...String& attrName, const String& def) const
^
1 warning generated.
g++-4.9不会给出类似的警告。
我认为clang是过分热心了,在这种情况下它应该工作得很好,因为我知道当这个函数被使用时,输入有足够长的生命周期。(我很确定我已经看到了大量的代码,似乎以这种方式工作…)
我有点害怕clang说它是一个"局部临时对象"。真的没有什么应该有一个本地临时对象,如果clang认为是这样的,并且在这个函数运行时正在删除东西,我想知道为什么。
标准是否保证这个函数返回的引用(在选择"def"的情况下)将与传入的引用具有相同的生命周期,或者是否允许将它们视为具有不同生命周期的两个不同引用?
不,不安全。
在本例中,三元条件操作符的计算结果为其操作数的副本。因此出现了警告。
你可以通过注入一个漂亮的小std::ref
来解决这个问题。
[C++11: 5.16/6]:
第二个和第三个操作数具有相同的类型;结果就是这种类型。如果操作数具有类类型,则结果是结果类型的右值临时值,根据第一个操作数的值从第二个操作数或第三个操作数复制初始化。
def
不是这里的临时对象。如果getValue
实际返回const String&
,则条件运算符也不会生成临时对象。
然而,这个函数的设计是危险的,因为它没有针对这样的错误的保护:
const String &bar = getValueAsString( "bla", "" ); // oops
从""
创建的临时字符串在getValueAsString
返回时死亡,因此bar
现在是一个悬垂引用(当然,如果触发了默认值)。
生命周期扩展仅在将临时对象直接绑定到引用时发生。从该引用初始化其他引用不会重新延长临时对象的生存期。
可能clang实际上检测到你的代码确实包含这个错误,即你在调用这个函数时绑定了一个临时的def