Подтвердить что ты не робот

Должен ли я предпочитать итераторы над const_iterators?

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

Вот несколько другой способ взглянуть на него. 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

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

Ответ 4

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

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

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

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

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

Ответ 5

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

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

Ответ 6

С++ 98

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

  • просто было непросто получить const_iterator для контейнера non const вообще
  • Если у вас есть 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 iterators легко получить с помощью cbegin и т.д. даже для контейнеров non const и всех (?) функций-членов, которые занимают позиции, имеют константные итераторы в качестве своих аргументов, поэтому нет необходимости в каком-либо преобразовании.

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

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

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

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

Предпочитают const_iterators над итераторами

так как первый является просто артефактом исторических дефицитов реализации.