On 30/10/13 10:00, Kai Tietz wrote: > 2013/10/30 Andrew Haley <a...@redhat.com>: >> On 10/30/2013 08:34 AM, Ondřej Bílka wrote: >> >>>> >>> The reasons of adding builtins is performance. Without that one can >>> write a simple template to generically check overflows like >>> >>> template <class C> class overflow { >>> public: >>> C val; >>> overflow <C> operator + (overflow <C> &y) { >>> overflow <C> ret; >>> if (val > 0 && y.val > 0 && val + y.val < val) >>> throw std::overflow_error(); >>> /* ... */ >>> ret.val = val + y.val; >>> return ret; >>> } >>> /* ... */ >>> }; >> >> How is that going to work? The compiler can simply eliminate this line: >> >> if (val > 0 && y.val > 0 && val + y.val < val) >> throw std::overflow_error(); >> >> because it knows that the guard is always false. I suppose it could be >> compiled with -fwrapv. >> >> Andrew. > > Right, as Andrew pointed out, this doesn't work. You are falling into > the pit of optimization on assumptions of overflow. > > The way, which might work, is to do checks on unsigned types. As for > unsigned-integer-scalar-types overflow is defined. > > Kai >
Technically speaking, casting your signed values to unsigned and using that to detect overflow will not necessarily work - I think it would be "implementation defined". But almost all architectures use two's compliment arithmetic, and it will work there. I don't know if this is legal C++ (I haven't had enough practice at this stuff), but the principle would be: if (val > 0 && y.val > 0 && (signed) ((unsigned C) val + (unsigned C) y.val) < val) throw std::overflow_error(); You also need: if (val < 0 && y.val < 0 && (signed) ((unsigned C) val + (unsigned C) y.val) > val) throw std::overflow_error();