4 ms·
I stopped doing this once 64 bits became a thing. There's nothing wrong per se with having your indexes signed, if you don't mind potentially not being able to
by to3m 12y ago
I stopped doing this once 64 bits became a thing. There's nothing wrong per se with having your indexes signed, if you don't mind potentially not being able to access the entire array - though I'm not convinced using int is very forward-thinking, as they're fairly reliably still 32 bits - but there's everything wrong with casting size_t to int.
For example, assuming 64 bit, suppose i is 0x1000 and container.size() is 0x100000fff. Now (int)container.size() is very likely to be 0xfff, meaning i is greater, and something goes wrong.
Or - and this would be very likely true for 32 bit systems as well - suppose container.size() is 0x80000000. Now (int)container.size() is -2147483648, meaning i is greater, and something goes wrong again.
A better option would be (assuming size_t is at least as wide as int, which is vanishingly unlikely not to be true on modern systems, and can anyway be checked for using a static assert) i>=0&&(size_t)i<container.size(). Then you know the cast won't produce nonsense.
- cannam 12y agoThat is a good point. The motivation for casting the size to int, rather than the other way around, is to get it out of "unsigned world" (where people often reason badly about even simple arithmetic) and into "signed world" as simply as possible. Often where this is going on, the container is expected to be small, but of course that's a hazardous intuition as well. Maybe I need a little helper: template<typename T, typename C> bool is_in_range(T i, const C &container) { if (i < 0) return false; if (sizeof(T) > sizeof(typename C::size_type)) { return i < static_cast<T>(container.size()); } else { return static_cast<typename C::size_type>(i) < container.size(); } } then if (is_in_range(i, container)) ...