7 ответов:
const_iterators не позволяют изменять значения, на которые они указывают, регулярныеiterators do.как и все вещи в C++, всегда предпочитаю
const, если нет веской причины использовать регулярные итераторы (т. е. вы хотите использовать тот факт, что они неconstдля изменения указанного значения).
они должны в значительной степени быть самодостаточной. Если итератор указывает на элемент типа T, то const_iterator указывает на элемент типа 'const T'.
это, в основном, эквивалентные типы указателей:
T* // A non-const iterator to a non-const element. Corresponds to std::vector<T>::iterator T* const // A const iterator to a non-const element. Corresponds to const std::vector<T>::iterator const T* // A non-const iterator to a const element. Corresponds to std::vector<T>::const_iteratorитератор const всегда указывает на один и тот же элемент, поэтому итератор является const. Но элемент, на который он указывает, не должен быть const, поэтому элемент, на который он указывает, может быть изменен. В const_iterator-это итератор, который указывает на элемент const, поэтому, хотя сам итератор может быть обновлен (например, увеличен или уменьшен), элемент, на который он указывает, не может быть изменен.
к сожалению, многие методы для контейнеров STL занимает итераторы вместо const_iterators как параметры. Так что если у вас есть const_iterator, вы не можете сказать "вставить элемент перед элементом, на который указывает этот итератор" (говоря, что такая вещь не является концептуально нарушением const, на мой взгляд). Если вы хотите сделать это в любом случае, вы должны преобразовать его в неконстантный итератор с помощью std:: advance () или boost:: next (). Например. boost:: next (контейнер.begin (), std::distance(container.begin (), the_const_iterator_we_want_to_unconst)). Если контейнер это std:: list, то времени для этого вызова будет O (n).
таким образом, универсальное правило для добавления const везде, где это "логично", является менее универсальным, когда речь заходит о контейнерах STL.
однако контейнеры boost принимают const_iterators (например. boost::unordered_map:: erase()). Поэтому, когда вы используете контейнеры boost, вы можете быть "const agressive". Кстати, кто-нибудь знает, будут ли исправлены контейнеры STL?
использовать const_iterator всякий раз, когда вы можете использовать итератор когда у вас нет другого выбора.
минимальный примеры
Неконстантные итераторы позволяют изменять то, на что они указывают:
std::vector<int> v{0}; std::vector<int>::iterator it = v.begin(); *it = 1; assert(v[0] == 1);Const итераторы не делают:
const std::vector<int> v{0}; std::vector<int>::const_iterator cit = v.begin(); // Compile time error: cannot modify container with const_iterator. //*cit = 1;как показано выше,
v.begin()иconstперегружен, и возвращает либоiteratorилиconst_iteratorв зависимости от постоянства переменной контейнера:
- как begin () знает, какой тип возврата возвращать (const или non-const)?
- как работает перегрузка функций const и non-const?
общий случай, когда
const_iteratorвсплывает, когдаthisиспользуется внутриconstспособ:class C { public: std::vector<int> v; void f() const { std::vector<int>::const_iterator it = this->v.begin(); } void g(std::vector<int>::const_iterator& it) {} };
constделаетthisconst, то, что делаетthis->vconst.вы обычно можете забыть об этом с
auto, но если вы начинаете передавать эти итераторы, вам нужно будет подумать о них для метода подписывание.так же, как const и non-const, вы можете легко конвертировать из non-const в const, но не наоборот:
std::vector<int> v{0}; std::vector<int>::iterator it = v.begin(); // non-const to const. std::vector<int>::const_iterator cit = it; // Compile time error: cannot modify container with const_iterator. //*cit = 1; // Compile time error: no conversion from const to no-const. //it = ci1;какой из них использовать: аналогично
const intvsint: предпочитайте итераторы const всякий раз, когда вы можете их использовать (когда вам не нужно изменять контейнер с ними), чтобы лучше документировать свое намерение читать без изменения.
(как говорили другие) const_iterator не позволяет изменять элементы, на которые он указывает, это полезно внутри методов класса const. Это также позволяет вам выразить свое намерение.
хорошо позвольте мне объяснить это с очень простым примером сначала без использования постоянного итератора рассмотрим, что у нас есть коллекция случайных целых чисел коллекция "randomData"
for(vector<int>::iterator i = randomData.begin() ; i != randomData.end() ; ++i)*i = 0; for(vector<int>::const_iterator i = randomData.begin() ; i!= randomData.end() ; ++i)cout << *i;Как видно для записи / редактирования данных внутри коллекции используется обычный итератор, но для чтения используется постоянный итератор . Если вы попытаетесь использовать постоянный итератор в первом цикле for, вы получите ошибку . Как правило большого пальца, использовать постоянный итератор для чтения данных в коллекцию .
Comments