There have already been some questions on this topic (1, 2, 3). The thing is that there doesn't seem to be a clear-cut answer. Some answers suggest size_t (1, 2), some suggest ptrdiff_t (1, 2). Other options include int, uint32_t, auto or using decltype on .size() of a container or the member type size_type.
This question may seem unsuitable as being opinion-based, but I don't think that's the case. Just because there isn't already a consensus on which type to use, doesn't mean that there cannot exist an objective answer. This is due to the fact that the different choices aren't only aesthetical, but can actually influence the behavior of the code.
For example, using an index variable type with mismatched signedness in the loop condition will cause compiler warnings, like this. Also, using a type that has a range that is too small can cause an overflow, which in the case of signed types is UB. At the same time, in some cases changing the loop counter type can cause "crazy performance deviations".
I also wanted to find out what is the most popular, though not necessarily the best, way to create for loop, so I used GitHub* search to find out. Here are the results:
| Loop type | Code result count on GitHub (averaged; "manual" loop + range-based) |
|---|---|
for (int |
15.8m |
for (size_t |
11.6m |
for (auto |
7.5m |
for (uint32_t |
2.3m |
std::for_each |
501k |
for (ptrdiff_t |
98.7k |
for (decltype |
77.5k |
There are certainly large differences in occurrence count between the different loop types, however, there doesn't seem to be a clear outstanding leader.
As such I post this question asking, what is the best type to use for the index variable in a for loop in C++ or what are the rules or conditions based on which this type should be chosen?
*: The GitHub search tool produces varying results for "code results" (count) each time, so I averaged 26 values. As the search is text-based it includes both results of the form for (int i = 0; i < n; ++i) and for (int i : vec).