Должен ли я предпочесть итераторы над const_iterators? - PullRequest
27 голосов
/ 19 апреля 2009

Кто-то здесь недавно поднял статью Скотта Мейерса, в которой говорится:

Кто-то еще комментировал, что статья, вероятно, устарела. Мне интересно, что вы думаете?

Вот мое: Один из основных пунктов статьи заключается в том, что вы не можете стереть или вставить на const_iterator, но я думаю, что это забавно использовать в качестве аргумента против const_iterators. Я думал, что весь смысл const_iterators в том, что вы вообще не изменяете диапазон, ни сами элементы, подставляя свои значения, ни диапазон, вставляя или стирая. Или я что-то упустил?

Ответы [ 6 ]

22 голосов
/ 19 апреля 2009

Я полностью согласен с вами. Я думаю, что ответ прост: Используйте const_iterators, где значения const правильные, и наоборот. Мне кажется, что те, кто против const_iterators, должны быть против const вообще ...

9 голосов
/ 19 апреля 2009

Вот немного другой взгляд на это. Const_iterator почти никогда не имеет смысла, когда вы передаете его в качестве указателя на определенную коллекцию и вы также передаете коллекцию. Мистер Мейер специально заявил, что const_iterator нельзя использовать с большинством функций-членов экземпляра коллекции. В этом случае вам понадобится обычный старый iterator. Однако, если у вас нет дескриптора коллекции, единственное различие между ними состоит в том, что вы можете изменить то, что указывает на , на iterator, и вы не можете изменить объект, на который ссылается const_iterator.

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

void some_operation(std::vector<int>& vec, std::vector::const_iterator pos);

не имеет большого смысла. Неявное утверждение состоит в том, что some_operation может свободно изменять базовую коллекцию, но не может изменять то, на что ссылается pos. Это не имеет особого смысла. Если вы действительно этого хотите, то pos должно быть смещением, а не итератором.

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

Надеюсь, что все стало ясно, как грязь;)

3 голосов
/ 13 октября 2009

Я обычно предпочитаю constness, но недавно натолкнулся на головоломку с const_iterators, которая запутала мою философию "всегда использовать const были возможны":

MyList::const_iterator find( const MyList & list, int identifier )
{
    // do some stuff to find identifier
    return retConstItor;
}

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

Интересно, может быть, тогда, если совет Скотта Майерса касается таких вопросов, когда становится невозможным избежать константности? Насколько я понимаю, вы не можете (надежно) неконстантных const_iterators с простым приведением из-за некоторых внутренних деталей. Это также (возможно, в сочетании) может быть проблемой.

это, вероятно, актуально: Как удалить константу const_iterator?

3 голосов
/ 19 апреля 2009

Я не думаю, что это конкретное утверждение Мейера нужно принимать с особой заботой. Если вам нужна немодифицирующая операция, лучше всего использовать const_iterator. В противном случае используйте обычный iterator. Однако обратите внимание на одну важную вещь: никогда не смешивайте итераторы, то есть const с non-const. Пока вы знаете о последнем, с вами все будет в порядке.

2 голосов
/ 22 августа 2017

C ++ 98

Я думаю, что нужно учитывать, что утверждение Мейерса относится к c ++ 98. Трудно сказать сегодня, но если я правильно помню

  • просто было непросто получить const_iterator для неконстантного контейнера вообще
  • если вы получили const_iterator, вы вряд ли могли бы его использовать, поскольку большинство (все?) Аргументов позиции для функций-членов контейнера должны были быть итераторами, а не const_iterators

например.

std::vector<int> container;

потребовалось бы

static_cast<std::vector<int>::const_iterator>(container.begin())

чтобы получить const_iterator, который значительно раздувал бы простой .find и даже если у вас был результат, то после

std::vector<int>::const_iterator i = std::find(static_cast<std::vector<int>::const_iterator>(container.begin()), static_cast<std::vector<int>::const_iterator>(container.end()),42);

не было бы никакого способа использовать ваш std :: vector :: const_iterator для вставки в вектор или любую другую функцию-член, которая ожидала итераторы для позиции. И не было никакого способа получить итератор от константного итератора. Для этого не было никакого способа литья.

Поскольку const-итератор не означает, что контейнер не может быть изменен, а только то, что указанный элемент не может быть изменен (const-итератор является эквивалентом указателя на const) , который действительно был большим куча дерьма, чтобы иметь дело с такими случаями.

Сегодня верно обратное.

const-итераторы легко получить с помощью cbegin и т. Д. Даже для неконстантных контейнеров и всех (?) Функций-членов, которые занимают позиции, в качестве аргументов используют const-итераторы, поэтому нет необходимости в каком-либо преобразовании.

std::vector<int> container;                
auto i = std::find(container.cbegin(), container.cend(), 42); 
container.insert(i, 43); 

Так, что когда-то было

Предпочитать итераторы, а не const_iterators

сегодня действительно действительно должно быть

Предпочитать const_iterators вместо итераторов

, поскольку первый - просто артефакт исторического дефицита реализации.

2 голосов
/ 19 апреля 2009

Читая эту ссылку, Мейерс, по-видимому, в основном говорит, что интегратор лучше, чем const_interator, потому что вы не можете вносить изменения через const_iterator.

Но если это то, что он говорит, то Мейерс на самом деле неправ. Именно поэтому const_iterator лучше, чем итератор, когда это то, что вы хотите выразить.

...