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