【问题标题】:Why is returning address of local variable or temporary only a warning and not an error?为什么返回局部变量或临时地址只是警告而不是错误?
【发布时间】:2015-06-03 11:26:52
【问题描述】:

刚刚收到编译器针对此函数的警告:

template<class T>
Matrix3x3<T> & operator - (Matrix3x3<T> const & p)
{
    auto m = Matrix3x3<T>(p);

    m.m11 = -m.m11; m.m12 = -m.m12; m.m13 = -m.m13;
    m.m21 = -m.m21; m.m22 = -m.m22; m.m23 = -m.m23;
    m.m31 = -m.m31; m.m32 = -m.m32; m.m33 = -m.m33;

    return m;
}

,我想知道为什么返回局部变量或临时地址的地址不会出错。在某些情况下您必须这样做吗?这只是“未定义的行为”而不是语言限制的理由是什么?

我想不出来。

【问题讨论】:

  • 可以在函数中声明为静态的。
  • 编译器不知道它是静态的吗?
  • 随机数生成 ;)
  • 如果我不得不猜测的话,可能是一些旧的 C 代码——可能是实现端而不是在应用程序库/代码中——故意返回这些值作为向例如报告堆栈使用情况的一种方式。与已知的堆栈限制相比,在失败前处理递归,选择缓冲区大小等。使用内联汇编获取堆栈指针更简单,但并非所有编译器都拥有/拥有。如果在表达式中做这样的事情(可能是宏替换),在调用上下文中创建一个本地变量将不是一个选项(没有像 GCC 的语句表达式扩展这样的东西)。
  • 在一般情况下(参见 Entscheidungsproblem),在使用它时找到所有肯定会导致未定义行为的地方是不可能的。我认为委员会不会要求“在可能的情况下发现错误,但有时你不能,所以......”。 (注意,如果你从不使用返回值,没有问题。)

标签: c++ compiler-warnings


【解决方案1】:

没有充分的理由说明它不应该是一个错误,只是 C++ standard 不会这样对待这种情况,并且符合标准的编译器会遵守标准。

但是,鼓励发出警告:

§12.2.5.2 临时绑定到函数返回语句 (6.6.3) 中的返回值的生命周期不会延长; 临时在 return 语句中的完整表达式结束时被销毁

[...]

[注意:这可能会引入悬空引用,鼓励实现 在这种情况下发出警告。 ——尾注]

重点是我的。

【讨论】:

  • 根据我链接的 C++14 草案标准的格式(参见第 271 页),我无法判断该注释是仅引用 12.2.5.3 还是引用整个12.2.5。后者是有道理的,但如果其他人可以对此发表评论,我将不胜感激。
  • N4296 是 C++1z 的草稿,在 C++14 最终版之后(这是 N4141,N4140 是最后的 C++14 草案)。关于您的问题,据我所知,示例和注释仅参考 [12.2p5.3]。当示例或注释引用整个列表时,它们的缩进与主要段落相同;有关此类格式的示例,请参见 [8.5.4p7](与 [8.5.4p3] 中的列表和示例对比)。更具建设性的是,您的答案仅涵盖在 return 语句中创建的临时变量,而不是问题中提到的局部变量。
【解决方案2】:

原因:生成编译器错误时缺乏一致性

在您直接的情况下,编译器实际上有助于生成警告。将其视为奖励
但请寻找以下编译器无法识别此问题的情况:

int& foo ()
{
  int i = 1;
  static int j;
  return i? i : j;  // No warning in g++-5!
}

现在从编译器的角度来看,如果它在一种情况下给出错误而在另一种情况下由于代码的复杂性而退缩是不合理的。

这种编译器限制的一个用例可以是“随机数生成”,正如@tsuki 所建议的那样。

【讨论】:

  • 所以从本质上讲,这样的情况实际上是编译器很难检测到的。
  • @Robinson,假设它很容易被发现。编译器仍然无法判断编码器的意图。例如如前所述,如果用户打算使用此类函数生成随机数,那么这是一个有效的操作,编译器不能通过生成错误来阻止它。
  • 你真的打开了警告吗?对于这种情况,GCC 确实会发出 return-local-addr 警告。
  • 我发现使用它来生成随机数非常不可信。我的意思是这是一个使用 yes 的例子,但是当我考虑到潜在的糟糕和/或错误代码时,我无法想象标准委员会会因为这样的原因让它通过。
  • @Robinson,我并不是说委员会引用了随机数用例作为理由。即使像(A*)(0)-&gt;foo() 这样的确定的镜头崩溃,编译器也可能不会产生错误。这并不意味着委员会批准它,而只是它不是编译器的责任。
猜你喜欢
  • 2019-06-15
  • 2011-04-13
  • 1970-01-01
  • 2012-01-01
  • 1970-01-01
  • 2022-01-17
  • 2011-10-17
相关资源
最近更新 更多