В чем разница между const-итератором и неконст-итератором в C++ STL?

в чем разница между const_iterator и iterator и где бы вы использовать один над другим?

7 ответов


const_iterators не позволяют изменять значения, на которые они указывают, regular 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, поэтому, хотя сам итератор может быть обновлен (увеличен или уменьшен, например), элемент, на который он указывает, не может быть изменен.


Unfortunaty, много методов для контейнеров STL принимает итераторы вместо const_iterators как параметры. Итак, если у вас есть const_iterator, вы не можете сказать "вставить элемент перед элементом, на который указывает этот итератор" (говоря, что такая вещь не является концептуально нарушением const, на мой взгляд). Если вы хотите сделать это в любом случае, вы должны преобразовать его в неконстантный итератор с помощью std:: advance () или boost:: next (). Например. boost:: next (контейнер.begin (), std::расстояние(контейнер.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() is const перегружен, и возвращает либо iterator или const_iterator в зависимости от постоянства переменной контейнера:

общий случай, когда 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 делает this const, то, что делает this->v const.

вы обычно можете забыть об этом с 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 int vs int: предпочитайте итераторы const всякий раз, когда вы можете их использовать (когда вам не нужно изменять контейнер с ними), чтобы лучше документировать свое намерение читать без изменения.


(как говорили другие) const_iterator не позволяет изменять элементы, на которые он указывает, это полезно внутри методов класса const. Это также позволяет вам выразить свое намерение.


ok позвольте мне сначала объяснить это очень простым примером без использования постоянного итератора рассмотрим, что у нас есть коллекция случайных целых чисел коллекции "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, вы получите ошибку . Как правило, используйте постоянный итератор для чтения данных внутри коллекции .