C ++: использование const с итераторами STL - PullRequest
2 голосов
/ 25 июля 2010

С Действительный 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 ]

8 голосов
/ 25 июля 2010

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

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

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

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

std::vector<int>::const_iterator ci

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

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

5 голосов
/ 25 июля 2010

Вы можете думать, что итераторы 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.

1 голос
/ 25 июля 2010

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

typedef int* Type;
typedef const int* ConstType;

int main() {
  const Type a; // int * const
  ConstType b; // const int *
}
1 голос
/ 25 июля 2010

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

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

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

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

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

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

0 голосов
/ 25 июля 2010

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

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

...