Несмотря на то, что ответ @JamesMcNellis является верным, я хотел бы объяснить кое-что об обработке ошибок, а также о том, что есть другой способ сделать то, что вы хотите.
У вас есть четыре способа доступа к определенному элементу в векторе:
- Использование оператора
[]
- Использование функции-члена
at(...)
- Использование итератора в сочетании с заданным смещением
- Использование
std::for_each
из заголовка algorithm
стандартной библиотеки C ++. Это еще один способ, который я могу порекомендовать (он использует внутренне итератор). Вы можете прочитать больше об этом, например, здесь .
В следующих примерах я буду использовать следующий вектор в качестве лабораторной крысы и объясню первые три метода:
static const int arr[] = {1, 2, 3, 4};
std::vector<int> v(arr, arr+sizeof(arr)/sizeof(arr[0]));
Это создает вектор, как показано ниже:
1 2 3 4
Сначала давайте посмотрим на []
способ ведения дел. Он работает почти так же, как вы ожидаете при работе с обычным массивом. Вы даете индекс и возможно вы получаете доступ к нужному элементу. Я говорю возможно , потому что оператор []
не проверяет, действительно ли вектор имеет столько элементов. Это приводит к молчаливому неверному доступу к памяти. Пример:
v[10] = 9;
Это может или не может привести к мгновенному сбою. Наихудший случай, конечно, если он этого не делает, и вы на самом деле получаете то, что кажется допустимым значением. Подобно массивам, это может привести к потере времени на поиск причины, почему, например, 1000 строк кода позже вы получаете значение 100
вместо 234
, что в некоторой степени связано с тем самым местом, где вы извлекаете элемент от вашего вектора.
Гораздо лучший способ - использовать at(...)
. Это автоматически проверит поведение out of bounds
и прервет бросок std::out_of_range
. Так что в случае, когда у нас есть
v.at(10) = 9;
Мы получим:
прекращение вызова после выброса экземпляра 'std :: out_of_range'
what (): vector :: _ M_range_check: __n (который равен 10)> = this-> size ()
(что 4)
Третий способ похож на оператор []
в том смысле, что вы можете все испортить. Вектор, как и массив, представляет собой последовательность непрерывных блоков памяти, содержащих данные одного типа. Это означает, что вы можете использовать свой начальный адрес, назначив его итератору, а затем просто добавив смещение к этому итератору. Смещение просто означает, сколько элементов после первого элемента вы хотите пройти:
std::vector<int>::iterator it = v.begin(); // First element of your vector
*(it+0) = 9; // offest = 0 basically means accessing v.begin()
// Now we have 9 2 3 4 instead of 1 2 3 4
*(it+1) = -1; // offset = 1 means first item of v plus an additional one
// Now we have 9 -1 3 4 instead of 9 2 3 4
// ...
Как видите, мы можем сделать
*(it+10) = 9;
, который снова является недопустимым доступом к памяти. По сути, это то же самое, что и at(0 + offset)
, но без проверки ошибок за пределами допустимого.
Я бы посоветовал использовать at(...)
всегда, когда это возможно, не только потому, что он более читабелен по сравнению с доступом к итератору, но и из-за проверки ошибок на недопустимый индекс, о которой я упоминал выше, как для итератора с комбинацией смещений, так и для оператора []
.