2015-06-18 4 views
0

Почему const STL контейнеры возвращаются только const_iterator s?Контейнеры const имеют только константный итератор?

Например, оба std::vector и std::list имеет метод begin перегруженного как:

iterator begin(); 
const_iterator begin() const; 
const_iterator cbegin() const; 

Я думал, что я все еще мог изменить значение константного вектора, но не сам вектор. Согласно стандартной библиотеке нет никакой разницы между:

const std::vector<int> 

и

const std::vector<const int> 
+0

Узел, что это: http://stackoverflow.com/questions/27065617/const-vector-implies-const-elements Не отвечает на мой вопрос. – biowep

+2

Разница между «значением» контейнера и контейнером не существует. Представьте себе, если бы вместо вектора мы говорили о целых числах. Что бы это значит сказать, что вы можете изменить значение целого числа, но не целое «сам»? –

+0

Возможный дубликат [В чем причина cbegin/cend?] (Http: // stackoverflow.com/questions/12001410/what-is-the-reason-behind-cbegin-cend) – CoryKramer

ответ

2

Предположим, у вас есть

iterator begin() const; 

вместо

const_iterator begin() const; 

Теперь подумайте, что происходит, когда у вас есть

const vector<Foo> v; 

Вы будете в состоянии сделать что-то вроде

*v.begin() = other_foo; 

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

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

+0

Но в списке или в более сложном контейнере (например, в дереве, которого не существует) контейнер сам остается константой, так как только его узел будет модифицирован '* v.begin() = other_foo;'. – biowep

+1

@biowep Зависит от того, как вы хотите, чтобы ваш интерфейс работал. Если вы хотите, чтобы 'const Container ' был эквивалентен 'Container ' (т. Е. Для сохранения логической константы), тогда решение должно использовать 'const_iterator'. Если нет, то, конечно, это зависит от вас, что вы возвращаете как итератор. Много раз это очень хорошая идея, но для сохранения логической константы, поскольку в противном случае вы можете получить очень тонкие ошибки. В общем, когда вы пишете 'const Container ', вы действительно имеете в виду контейнер, элементы которого нельзя изменить. – vsoftco

0

Если вы объявите свой вектор, как

const std::vector<int> foo; 

Тогда сам вектор const, то есть вы не можете push_back , erase и т. Д. Однако вы можете изменить его элементы

for (std::vector<int>::iterator it = foo.begin(); it != foo.end(); ++it) 
{ 
    int& x = *it; 
    x++;   // This is fine! 
} 

При перебрать вектор, вы исполнение, что элементов вектора являются const. Таким образом, вы можете изменять вектор, добавляя и удаляя вещи, но вы не можете изменять фактические элементы.

std::vector<Foo> values; // Neither the vector nor its elements are const 

for (std::vector<Foo>::const_iterator it = values.cbegin(), it != values.cend(); ++it) 
{ 
    Foo const& foo = *it;   // I may not try to modify foo 
    it->CallToNonConstMethod(); // Can't do this either 
}