Expressions and statements
ES.107
Не используйте `unsigned` для индексов, предпочитайте `gsl::index`
Причина
Чтобы избежать путаницы знаковых и беззнаковых. Для возможности лучшей оптимизации. Для лучшего обнаружения ошибок. Чтобы избежать ловушек с auto и int.
Пример (плохой)
vector<int> vec = /*...*/;
for (int i = 0; i < vec.size(); i += 2) // может быть недостаточно широким
cout << vec[i] << '\n';
for (unsigned i = 0; i < vec.size(); i += 2) // риск завёртывания
cout << vec[i] << '\n';
for (auto i = 0; i < vec.size(); i += 2) // может быть недостаточно широким
cout << vec[i] << '\n';
for (vector<int>::size_type i = 0; i < vec.size(); i += 2) // многословно
cout << vec[i] << '\n';
for (auto i = vec.size()-1; i >= 0; i -= 2) // ошибка
cout << vec[i] << '\n';
for (int i = vec.size()-1; i >= 0; i -= 2) // может быть недостаточно широким
cout << vec[i] << '\n';
Пример (хороший)
vector<int> vec = /*...*/;
for (gsl::index i = 0; i < vec.size(); i += 2) // ok
cout << vec[i] << '\n';
for (gsl::index i = vec.size()-1; i >= 0; i -= 2) // ok
cout << vec[i] << '\n';
Примечание
Встроенный массив допускает знаковые индексы. Контейнеры стандартной библиотеки используют беззнаковые индексы. Таким образом, идеального и полностью совместимого решения не существует (пока контейнеры стандартной библиотеки не перейдут когда-нибудь в будущем на знаковые индексы). Учитывая известные проблемы с беззнаковыми и смешанными знаковыми/беззнаковыми значениями, лучше придерживаться (знаковых) целых чисел достаточного размера, что гарантирует gsl::index.
Пример
template<typename T>
struct My_container {
public:
// ...
T& operator[](gsl::index i); // не беззнаковый
// ...
};
Пример
??? демонстрация улучшенной кодогенерации и возможности обнаружения ошибок ???
Альтернативы
Альтернативы для пользователей:
- использовать алгоритмы
- использовать range-for
- использовать итераторы/указатели
Контроль
- Очень сложно, пока контейнеры стандартной библиотеки делают это неправильно.
- (Во избежание лишних предупреждений) Не отмечать смешанные знаковые/беззнаковые сравнения, где один из аргументов —
sizeofили вызов.size()контейнера, а другой —ptrdiff_t.