Boost logo

Boost :

From: Alexander Grund (alexander.grund_at_[hidden])
Date: 2020-03-02 09:16:14

Am 28.02.20 um 21:15 schrieb degski via Boost:
> On Fri, 28 Feb 2020 at 17:48, Alexander Grund via Boost <
> boost_at_[hidden]> wrote:
>> There exists no negative size.
> This IS exactly why you should use signed int's
So to represent a number that is always unsigned you should use a signed
> , so overflow is easy to detect.
That is a different use case: An operation, not a representation.
Nothing stops you from converting to signed, do what you want including
your "check for negative"-based overflow detection and finally
converting back to unsigned when passing it to an API expecting an
unsigned number (number not type, although the type is unsigned too, see
> By the time you (I don't mean You of course, sorry for my bad
> english) wrapped almost (a little bit less than 2^64) around the
> std::size_t integer line
Didn't you argue in the mail before that there will never be anything of
size 2^32 and hence even not anything like 2^64? How could you overflow
that then?
> Finding bugs related to this is hard, using int's you'll know right away.
How? Only if you underflow. On unsigned you'll get a very large number
if you go below zero, on signed you get a negative number. Both can be
detected. But you talked about overflow. For unsigned you'll get a small
number (that is wrong obviously but you COULD check) but for signed you
get UB and hence can't even check for that.
>> If you get an unsigned
>> value there is no need to check for below zero, if you get a signed
>> value you might. It is the same there is `not_null<T>` in GSL(?).
> But you would need to check if it wrapped
No. If you call `obj.size()` you get an unsigned value that is a valid
unsigned value. It cannot wrap when returning (conditions apply).
If obj.size() returns a signed value you'll got to check for <0 before
using the value unless the API somehow promises to not return negative
values. Encoding this in the type is the natural thing to do.
> and if you start adding and subtracting these things
See above. For a representation (and hence API) unsigned makes sense.
For using arbitrary operations it may not. Use the types that fir your
use case. Adding is save for unsigned, as you argued: The type is wide
enough for all uses as a size of something. Subtraction might not but
you can check first (`if(a <= size) return size - a; else throw `)
> (the int's should be
> sized to requirement of course like OP has implemented, I applaud this, now
> it only needs to also be possible to make that signed).
You mean different widths? You'll still have to check if you can
"downcast/narrowcast" it before doing so.
> The whole discussion just shows that there is a problem with operations
>> mixing signed and unsigned types in C++ in general.
> Yes, solution: signed, slightly (a power of 2, :-) ) smaller, but that is
> not relevant for actual 'problems' in this (our) world.
See above: Use signed for operations if you want to detect underflow.
>> What we probably wanted was something like `size_t = not_negative<int>`, but well...
> I don't understand.

Maybe after the above? You want a guarantee to have a non-negative
number. "unsigned" is that but it suffers from underflow going
undetected. A `not_null<T>` like "wrapper" which otherwise behaves as T
but guarantees the non-negativity would make the type suitable for
representing an unsigned number in a signed type suitable for
operations. Obviously if you subtract something from a
`not_negative<int>` it will become a plain "int". Once you pass it to an
API expecting a `not_negative<int>` the precondition will be checked.

Boost list run by bdawes at, gregod at, cpdaniel at, john at