Почему для счётчиков не используют беззнаковые (unsigned) числа?
У std::vector как раз не int, а size_t, который алиас для unsigned long.
В результате строгий компилятор на действия индексной арифметики, где, внезапно, вполне могут использоваться отрицательные числа, сыплет предупреждениями о том, что вместо беззнакового числа получается знаковое, ай-яй-яй. И оно с одной стороны правильно, потому что отрицательных индексов, скорее всего, не предполагается и тут могут крыться ошибки, а с другой - ну что программист с этим сделает? Приведет к беззнаковому и вместо одной ошибки спровоцирует другую?
В целом - так исторически сложилось, что в C# используется знаковый тип для индексации массивов.
В Java вообще, например, нет беззнаковых типов. (думаю, из-за этого и в C# для индексации используется int)
В новых языках, например в Rust от этого сразу уходят - в нём для индексации массивов используется usize (беззнаковый, размером с указатель на целевой машине)