C++: использование const с итераторами STL

Из эффективного C++, пункт 3

/* case1 */ const std::vector<int>::iterator i  // i  acts like a T* const
/* case2 */ std::vector<int>::const_iterator ci // ci acts like a const T*

Вспомнить как const применяется, я раньше помнил следующее из этой статьи

По сути, "const" относится к тому, что находится непосредственно слева от него (кроме случаев, когда там ничего нет, в этом случае оно применяется к тому, что непосредственно справа от него).

Когда я сначала прочитал пункт 3 в книге, я ожидал, что он будет наоборот в случае 1 и 2.

Должен ли я рассматривать этот случай как исключение? Или есть какое-то более глубокое понимание того, что мне не хватает?

5 ответов

Правило работает как рекламируется.

const std::vector<int>::iterator i

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

Это редко желаемое поведение, поэтому const_iterator typedef существует.

std::vector<int>::const_iterator ci

Итератор можно перемещать, но указанный элемент не может быть изменен. Это почти всегда то, что вы хотите - вы хотите перебирать вектор, но не можете изменять его содержимое.

Нет никаких const здесь ключевое слово, так что вы не можете использовать правило, чтобы понять это. Для этого вам просто нужно понять, что const_iterator задокументировано сделать.

Вы можете думать об этом, как будто итераторы typedefРед так:

typedef T* iterator;
typedef const T* const_iterator;

Когда вы добавляете const к любому из них это относится на верхнем уровне, то есть к самому указателю, а не к указанному объекту, поэтому выполняются следующие эквивалентности:

const iterator it; // is the same as:
T* const it;

const const_iterator it; // is the same as:
const T* const it;

Они не являются исключением; вот как все typedefс работой.

Я думаю, что const_iterator сбивает вас с толку. Вот пример с более простыми typedefs.

typedef int* Type;
typedef const int* ConstType;

int main() {
  const Type a; // int * const
  ConstType b; // const int *
}

Указанное правило абсолютно верно для const ключевое слово. Однако при работе с итераторами const_iterator класс просто назван так (это может быть readonly_iterator), так что правило о const Ключевое слово не применяется.

Однако вы можете объявить случай 1 следующим образом:

std::vector<int>::iterator const i

так же, как вы можете указать либо const int x или же int const x,

Тип, на который указывает итератор, также указывается в параметре шаблона его контейнера, поэтому порядок отличается от объявления обычных переменных.

Я не вижу, чтобы здесь было какое-то конкретное эмпирическое правило - комментарии в вашем посте - правильная идея, вам просто нужно научиться относиться к ним. const_iterator как const T* и так далее.

const в случае 1 применяется к итератору, поэтому он делает сам итератор постоянным. Это не влияет на элемент, на который "указывает" итератор. (Это как в T* constгде указатель constне указали T)

В случае 2 const это просто часть имени const_iteratorтак что на самом деле не может быть выведено, что const там. У класса может быть просто плохое имя, и в этом не может быть ничего постыдного. В этом случае, однако, const_iterator не позволяет модифицировать его целевой элемент, потому что он определен так в стандартной библиотеке.

Другие вопросы по тегам