5

由于返回对局部变量的引用,我刚刚被一个令人讨厌的未定义行为所困扰。

我们知道这是邪恶的,通常编译器会打印出一个很好的信息warning来告诉我们......不过 gcc (3.4.2) 似乎并没有将检查推得太远。

std::string get_env_value(std::string const& key);

std::string const& get_phase()
{
  std::string const& phase = get_env_value("PHASE"); // [1]
  std::cout << "get_phase - " << phase << '\n';
  return phase;                                      // [2]
}

这编译没有故障,但我们陷入了未定义行为的令人讨厌的领域。

[1]是可以的,因为标准规定绑定到 const 引用的变量的生命周期应该延长以匹配 const 引用的生命周期。

线[2]好像也不错。。。

  • C++ 规范是否涵盖这种情况?
  • 有谁知道这是否通常被诊断出来?(我可能会错过一面旗帜或其他东西......)

在我看来,静态分析应该能够说明对 , 使用“终身扩展”是不安全的,但我猜它可能会迅速变得丑陋[1]......[2]

4

2 回答 2

5

该标准不涵盖[2]. 它允许将右值绑定到 const 引用,但这不允许您返回 const 引用并延长它绑定到的右值的生命周期。

确实,静态分析可以捕捉到这一点,但与往常一样,这是一种权衡。C++ 编译本身就足够慢,因此编译器编写者必须权衡进一步静态分析的好处,这可能使他们能够产生更好的诊断,与增加的编译时间。

于 2010-09-15T12:44:04.177 回答
2
  1. 不,我认为标准没有提到/涵盖这种特定情况。

  2. VS 2010 给出编译警告(/Za、/W4)。

所以,绝对它看起来是一个可诊断的条件。

所以,我稍微调整了函数如下,只是为了创建多个返回路径:

std::string const& get_phase() 
{ 
    std::string const& phase = get_env_value("PHASE"); // [1] 
    std::cout << "get_phase - " << phase << '\n'; 

    if(1){
        while(1){
            return phase;
        }
    }
    return phase;                                      // [2] 
} 

现在,VS 不会像之前那样报告警告。

例如,乍一看,编译器应该很容易检测并捕获并非所有路径都返回值。但是编译器(例如VS)没有。

int get_phase() 
{
    char ch;
    if(ch){
        return 0;
    }
     // nothing returned from here.
} 

所以,我猜 OP 中的代码可能与上面显示的示例具有相同的诊断条件的复杂性,尽管我不确定。唯一的好处是标准对这种情况很清楚。

$6.6.3/2 - “从函数末尾流出相当于没有值的返回;这会导致返回值的函数出现未定义的行为。”

回到 OP 中的代码,我猜该标准并未强制将此条件作为可诊断条件,因此编译器可以随心所欲地进行操作。基本上可以理解,返回的引用指向了一个已经被破坏的对象。所以访问这样的对象会导致未定义的行为

于 2010-09-15T13:05:15.347 回答