安全地返回 const 和 const 传递的对象 &?



使用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

最新更新