2013-12-25 6 views
1

Я пишу тестовый код, чтобы узнать, может ли итератор вектора быть за итератором конца(), как это.Почему итератор вектора STL указывает на элемент, который не существует?

#include <vector> 
#include <iostream> 
using namespace std; 

int main() 
{ 
    vector<int> v; 
    v.push_back(100); 
    cout << v.capacity() << endl; 
    vector<int>::iterator itr = v.begin(); 
    for (int i = 0; i < 10000; ++i, ++itr) 
     if (itr == v.end()) cout << "end at " << i << endl; 
    cout << *itr << endl; 
    return 0; 
} 

результат печати:

1 
end at 1 
0 

вектор v объект имеет только один потенциал, но его итератора может получить доступ к памяти после того, как конец() итератора. Есть ли защита для этой ситуации?

+2

Это неопределенное поведение, и стандартные мандаты не защищают от этого. – juanchopanza

+3

Вы имеете в виду кроме того * не * делает это? – WhozCraig

+0

Потому что он добавляет накладные расходы для проверки. –

ответ

6

Итераторы не защищают от доступа к элементам, которых там нет, поскольку они должны гарантировать минимальные накладные расходы. То же самое справедливо и для std::vector::operator[]. Доступ к элементу на уровне std::vector::end() или за его пределами, используя один из этих методов, дает неопределенное поведение, и нет возможности обнаружить его после факта.

Однако функция std::vector::at() выполняет функции std::out_of_range в этих случаях. Это исключение можно поймать и обработать изящно. Внедрение этой функции для итераторов приведет к накладным расходам во время выполнения из-за проверки границ. Это также привело бы к косвенным накладным расходам, потому что теперь итератору нужно было бы не только знать о текущем элементе, но и о векторе, который он итерации.

0

Некоторые версии стандартной библиотеки поставляются с проверенными итераторами для отладочных сборников. Они будут испускать диагностические ошибки, если вы попытаетесь использовать их неправильно.

Я знаю, что по крайней мере VS 2005+ (ака Dinkumware), STLport и libstdC++ могут это сделать.

1

С векторным доступом, capacity собственности менее интересно, чем size. Формет содержит внутренний размер буфера, а последний содержит количество хранимых элементов. Всегда count <= capacity.

С учетом сказанного, векторы были разработаны, чтобы заменить/обновить C массивы, поэтому их конструкция определяет неявно следующее:

  • Населенный пункт: все элементы хранятся в одном последовательном буфере.
  • Скорость: для увеличения скорости не выполняется никаких проверок границ.

Последнее не относится к отладки версий, которые могут реализовать граничную проверку и проверку итератора.

Для итерации вектора нам один из следующих фрагментов кода:

for (vector<int>::iterator itr = v.begin(); itr != v.end(); ++itr) { 
    int item = *itr; 
... 
} 

Или

size_t size = v.size(): 
for (size_t i = 0; i < size; ++i) { 
    int item = v[i]; 
... 
} 

Примечания: оба фрагмента кода предположит, что вы не добавлять или удалять элементы из вектора.

+1

Это не отвечает на вопрос. – juanchopanza

+0

Да, спасибо за ваш любезный ответ, я знаю, что вы сказали. возможно, я не описываю свою идею должным образом.вектор всегда сохраняет блок памяти для хранения своих элементов, объект-итератор _itr_ в моем тестовом коде может обращаться к памяти за пределами памяти, полученной векторным объектом. – Jeff

+0

Я обновил ответ. – egur

Смежные вопросы