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



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

1127   7  

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

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

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

    Ничего не найдено.