В чем разница между const_iterator и неконстантным итератором в C ++ STL? - PullRequest
110 голосов
/ 21 ноября 2008

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

Ответы [ 7 ]

100 голосов
/ 21 ноября 2008

const_iterator s не позволяют вам изменять значения, на которые они указывают, обычные iterator s делают.

Как и во всех вещах в C ++, всегда предпочитайте const, если только нет веской причины использовать обычные итераторы (т. Е. Вы хотите использовать тот факт, что они не const, чтобы изменить указанное значение).

34 голосов
/ 21 ноября 2008

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

7 голосов
/ 02 сентября 2010

К сожалению, многие методы для контейнеров STL принимают итераторов вместо const_iterators в качестве параметров. Поэтому, если у вас есть const_iterator , вы не можете сказать «вставить элемент перед элементом, на который указывает этот итератор» (говоря, что, на мой взгляд, такая вещь не является концептуальным нарушением const). В любом случае, если вы хотите сделать это, вам нужно преобразовать его в неконстантный итератор, используя std :: advance () или boost :: next () . Например. boost :: next (container.begin (), std :: distance (container.begin (), the_const_iterator_we_want_to_unconst)) . Если container является std :: list , то время выполнения этого вызова будет O (n) .

Таким образом, универсальное правило добавлять const везде, где это «логично», менее универсально, когда речь идет о контейнерах STL.

Однако контейнеры boost принимают const_iterators (например, boost :: unordered_map :: erase ()). Поэтому, когда вы используете буст-контейнеры, вы можете быть «агрессивными». Кстати, кто-нибудь знает, когда или когда контейнеры STL будут исправлены?

5 голосов
/ 21 ноября 2008

Используйте const_iterator всякий раз, когда можете, используйте итератор , когда у вас нет другого выбора.

1 голос

Минимальные примеры

Неконстантные итераторы позволяют вам изменять то, на что они указывают:

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 в зависимости от постоянства переменной контейнера:

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

0 голосов
/ 17 января 2011

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

0 голосов
/ 21 ноября 2008

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

...