【问题标题】:How can I avoid unexpected results from std::abs?如何避免 std::abs 的意外结果?
【发布时间】:2018-10-16 03:00:06
【问题描述】:

我遇到了几个不同的例子,说明std::abs 可以产生意想不到的结果:

  1. 这个问题(On the std::abs function)指出<cstdlib> 为整数类型提供重载,而<cmath> 为浮点类型提供重载。未能包含正确的标头会导致未定义的行为,允许编译器静默接受
  2. C++ Defect report 2735 指出 C++11 和 C++14 标准在技术上要求 std::abs(short) 返回 double,尽管大多数编译器会忽略相关措辞并返回 int。此问题的解决方法表明 C++17 中的措辞已更改,因此 std::abs(short) 返回 int
  3. 这个问题的答案 (When do I use fabs and when is it sufficient to use std::abs?) 指出依赖 std::abs 会导致难以发现的错误,因为(在现代 C++ 中)引入 std::abs 的标头允许引入全局abs 函数(可能有也可能没有相同的重载),很容易不小心使用abs 而不是std::abs

我知道的修复是:

  1. 避免未定义的行为:如果评估std::abs([integral type]),则包括<cstdlib>,如果评估std::abs([floating point type]),则包括<cmath>
  2. 两个选项:
    • 使用 C++17 或 pre-(C++11)
    • 根据编译器是否符合 C++11/C++14 标准,解决 std::abs(short) 可能返回 intdouble 的问题
  3. 两个选项:
    • 将标志 –Wconversion 传递给 gcc,以便像 abs(2.0) 这样的调用在编译时触发警告
    • 使用技巧(改编自 n.m. 对 (Disable math.h crap when working with cmath) 的回答)使全局 abs 模棱两可

技巧:

namespace neveruse{
    int abs(int);
}

using namespace neveruse;

问题:是否有理由更喜欢问题 3 的解决方案之一?这些修复中的任何一个是否会引入我需要注意的其他潜在问题?

【问题讨论】:

  • 我经常用auto i_am_also_a_float = fabsf(i_am_a_float);
  • 您能否准确说明您要避免的缺陷。这个问题是否只询问 std::abs(short) 返回双精度和整数的问题? (你还想要哪个?)
  • 我很想知道问题 3 的解决方案是否更好,以及问题 1 或 2 的任何解决方案是否有我可能没有考虑过的副作用(例如容易犯类似忘记 std:: 的其他错误。
  • 我认为这个技巧没有任何帮助,因为它会阻止 ::abs(...) 的使用,而语言缺陷会影响 std::abs(.. .)
  • “来自 std::abs 的意外结果”包括 abs(INT_MIN)

标签: c++ language-lawyer


【解决方案1】:

创建您自己的头文件,定义inline 函数absolute,该函数又包含所有正确的头文件并修复返回类型的错误,并调用std::abs

那么,不要使用absstd::abs(或任何名为abs 的令牌)。在 git commit(或您正在使用的任何版本管理系统)而不是在该文件中强制执行此操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-10
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 2016-02-28
    • 2014-10-14
    • 2021-08-04
    相关资源
    最近更新 更多