代码之家  ›  专栏  ›  技术社区  ›  Matthieu M.

编译器检测返回对局部变量的引用

  •  5
  • Matthieu M.  · 技术社区  · 14 年前

    由于返回对局部变量的引用,我刚刚被一个讨厌的未定义行为咬了一口。

    我们知道它是邪恶的,通常编译器会打印一个 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] 是可以的,因为该标准指定绑定到常量引用的变量的生存期应延长以匹配常量引用的生存期。

    线 [2] 看起来也不错…

    • C++规范涵盖了这个案例吗?
    • 有人知道这是不是通常被诊断出来的?(我可能会错过一面旗子或什么……)

    在我看来,静态分析应该能够告诉我们,在 [ 1 ] , 〔2〕 不安全,但可能会很快变丑…

    2 回复  |  直到 14 年前
        1
  •  5
  •   Stack Overflow is garbage    14 年前

    本标准不包括 [2] 。它允许将一个右值绑定到一个常量引用,但这不允许您返回一个常量引用并延长它绑定到的右值的生存期。

    以及真实的静态分析 能够 抓住这个,但和往常一样,这是一种权衡。C++编译是足够慢的,因此编译器编写者必须权衡进一步静态分析的好处,这可能允许他们产生更好的诊断,而不是增加编译时间。

        2
  •  2
  •   Chubsdad    14 年前
    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中的代码,我想标准并没有规定这个条件是一个可诊断的条件,因此编译器可以自由地做他们想做的事情。基本上可以理解,返回的引用指向一个已经被销毁的对象。因此访问这样的对象将导致未定义的行为