11

I've come across a few different examples of ways in which std::abs can give unexpected results:

  1. This question (On the std::abs function) points out that <cstdlib> provides overloads for integral types while <cmath> provides overloads for floating point types. Failing to include the correct header gives undefined behaviour, which the compiler is allowed to silently accept
  2. C++ Defect report 2735 points out that the C++11 and C++14 standards technically require that std::abs(short) returns a double, although most compilers ignore the relevant wording and return an int. The resolution to this issue indicates that the wording was changed in C++17 so that std::abs(short) returns an int
  3. The answers to this question (When do I use fabs and when is it sufficient to use std::abs?) point out that relying on std::abs can lead to difficult-to-spot bugs, since (in modern C++) the headers which introduce std::abs are allowed to introduce a global abs function (which may or may not have the same overloads), and it's easy to accidentally use abs instead of std::abs

The fixes that I am aware of are:

  1. Avoid undefined behaviour: include <cstdlib> if evaluating std::abs([integral type]) and <cmath> if evaluating std::abs([floating point type])
  2. Two options:
    • Use C++17 or pre-(C++11)
    • Work around the fact that std::abs(short) may return an int or a double depending on the compiler's compliance with the C++11/C++14 standard
  3. Two options:
    • Pass gcc the flag –Wconversion so that calls like abs(2.0) trigger a warning at compilation
    • Use a trick (adapted from n.m.'s answer to (Disable math.h crap when working with cmath)) to make to the global abs ambiguous

Trick:

namespace neveruse{
    int abs(int);
}

using namespace neveruse;

Question: Is there a reason to prefer one of the solutions to issue 3 over the other? Do any of these fixes introduce other potential problems that I need to watch out for?

user1476176
  • 1,045
  • 1
  • 7
  • 15
  • 1
    I often use `auto i_am_also_a_float = fabsf(i_am_a_float);` – Mikhail May 05 '18 at 23:43
  • 1
    Could you clarify exactly which defect you're trying to avoid. Is this question only asking about the problem with std::abs(short) returning doubles and ints? (Also which do you want?) – Mikhail May 05 '18 at 23:44
  • I'm interested in knowing whether either of the solutions to issue 3 is better, but also whether any of the solutions to issues 1 or 2 has side-effects that I might not have considered (such as making it easy to make other mistakes akin to forgetting std:: ). – user1476176 May 05 '18 at 23:48
  • I don't think, that the Trick is of any help, because it stops the ::abs(...) from beeing used, while the language defect affects std::abs(...) – kiloalphaindia May 06 '18 at 00:01
  • "unexpected results from std::abs" include `abs(INT_MIN)`. – chux - Reinstate Monica May 11 '18 at 19:16

1 Answers1

5

Create a header file of your own that defines an inline functionabsolute that in turn includes all the correct headers and fixes bugs with return types, and calls std::abs.

Then, don't use abs or std::abs (or any token named abs). Enforce this at git commit (or whatever version management system you are using) other than in that file.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524