🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

C++ size_t for everything?

Started by
30 comments, last by frob 4 years, 7 months ago
13 hours ago, Bregma said:

Yes. std::size_t is always the appropriate type to express sizes.

An index is not a size, it's a difference.  It should be expressed as a signed integer.

An index points to something that does have a size, so as far as the range of the values of allocation size and the index that navigates it... there's no real difference.

If you're unsure about the size of the data that you're iterating through, use size_t.  If you know the max size, then use the appropriate type.

Advertisement
On 11/8/2019 at 8:21 PM, 0r0d said:

An index points to something that does have a size, so as far as the range of the values of allocation size and the index that navigates it... there's no real difference. 

An index is a difference between the start of a sequence and a particular element within a sequence.  That's not a size, it's a difference.  If you have a sequence container it can be perfectly reasonable to index backwards from the end -- a negative value by conventional algebraic definitions.  It's not reasonable to have a size of less than zero, but consider the popular construct  for(auto i = my_array.size()+1; i-->0;) { ... }.

If you need to use a standard integral type to represent an index, std::ptrdiff_t is the better choice.  Perhaps it wasn't what Alexander Stepanov chose for his STL back in 1995, but its what the ISO-standard language provides for its built-in container type.

Stephen M. Webb
Professional Free Software Developer

The language clearly stipulates that the appropriate type for indexing containers is the member type size_type, which is always an unsigned integer type. So preference aside, unless you want to litter your code with casts every time you get close to accessing a container, I would go with that until you have a good reason not to.

You can think of the index of an element in a vector as the number of elements that come before it.

This observation is more philosophical than practical, but it lends some support to the decision of using the same type for sizes and indices.

 

12 hours ago, Bregma said:

It's not reasonable to have a size of less than zero, but consider the popular construct  for(auto i = my_array.size()+1; i-->0;) { ... }.

That "+1" seems like a bug to me. If `my_array' has N elements, that loop will run N+1 times, the first of which will go one element too far.

Auto is for those without compassion.

Dunno, some if not many situations need operations on the indices, that include comparisons with signed variables, subtractions, counting in a loop by steps !=1, etc., so many opportunties to miss the 0, wrap around, narrow ranges, hide things behind work-arounds and casts if sticking to unsigned too long.

This may be qualitative, semantic, relative, whatever, but i don't see it so strictly. One could even question the stl guys' decision to choose unsigned integers for indexing. It is narrowing. But so it is. Yet signed integers have their place. Just because they could make off by one errors less catastrophical :-)

There are basically three valid reasons to choose an unsigned integer type:

  1. Your integer is really a bit mask.
  2. You need wrapping behaviour on overflow.
  3. You need a type with that extra bit of range on the positive side.

The C++ standard library probably uses std::size_t for indices for the third reason.  During the early days of C++, 16-bit computers (with 16-bit pointers and 16-bit std::size_t) were still in use, and it was not uncommon to have arrays too large to be indexed with a 16-bit signed integer on a 16-bit computer.

11 hours ago, alvaro said:

That "+1" seems like a bug to me. If `my_array' has N elements, that loop will run N+1 times, the first of which will go one element too far. 

The "+1" is correct because "i" is decreased after the comparison inside the comparison statement of the for-loop. This happens before the body is executed. In the signed version, "i" is increased after the loop's body is executed.

WRONG --- See answers below

Greetings

Haha, now, if that discussion is not an argument pro signed integers in loops, just to avoid confusions, then i don't know what ...

Just trying to be funny?

 

p.s.: have you tried it, with a std::array and the range checking at(), counting down ?

19 minutes ago, DerTroll said:

The "+1" is correct because "i" is decreased after the comparison inside the comparison statement of the for-loop. This happens before the body is executed. In the signed version, "i" is increased after the loop's body is executed.

After i is decreased once, it has tha value of size, which is still one too much and it is a bug.

This is correct: for (i=stuff.size(); i-->0;)

This is wrong: for (i=stuff.size()+1; i-->0;)

Otherwise i know where all my bugs come from... :)

 

 

This topic is closed to new replies.

Advertisement