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

Почему итераторы должны быть конструктивными по умолчанию

Итераторы категорий вперед, двунаправленный и произвольный доступ должны быть конструктивными по умолчанию.

Почему это и почему операторы ввода и вывода не должны быть конструктивными по умолчанию?

4b9b3361

Ответ 1

Итераторы вперед и сильнее должны ссылаться на некоторую внешнюю последовательность (см. [forward.iterators]/6, в которой говорится: "Если a и b являются разыменованными, то a == b тогда и только тогда, когда *a и *b привязаны к одному и тому же объекту." )

Это означает, что они, как правило, просто облегчают работу над чем-то другим (например, указатель на элемент или node в контейнере), и поэтому нет оснований не требовать, чтобы они могли быть сконфигурированы по умолчанию (даже если по умолчанию конструкция создает единый итератор, который не может использоваться ни для чего, пока не будет присвоено новое значение). Для всех непатологических * форвардных итераторов возможно поддерживать конструкцию по умолчанию, и, опираясь на это, упростить реализацию некоторых алгоритмов.

Итераторы, которые удовлетворяют только требованиям ввода итератора или вывода итератора (и ничего более сильного), могут содержать состояние внутри себя, которое изменяется с помощью operator++, и поэтому может быть невозможно, чтобы это состояние было построено по умолчанию. Никакой алгоритм, который работает только на итераторах ввода/вывода, должен по умолчанию строить их, поэтому он не требуется.

  • укажите аргумент "нет истинного шотландца" здесь;)

Ответ 2

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

Операторы ввода и вывода часто наиболее элегантно реализуются со ссылками на базовый поток или другие объекты ввода-вывода, и ссылки должны быть инициализированы при построении. Конечно, реализации могут быть вынуждены отложить это и использовать указатели внутри страны, но, конечно же, чтобы натолкнуть некоторых людей на неправильный путь - кажется слишком "C" - например, так что неудивительно, что стандарт облегчает использование ссылок.

Ответ 3

ссылка для итераторов

Итераторы ввода/вывода:

Input Iterator: после того, как значение InputIterator я было увеличено, все копии его предыдущего значения могут быть аннулированы.

Выходной Iterator: после этой операции r не требуется быть разыменованным и любые копии предыдущего значения r больше не требуются разыскиваемый или увеличивающийся.

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

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

Итераторы вперед:

Это первый уровень итераторов, требующих конструкторы по умолчанию, но почему?

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

Однако есть одна довольно веская причина:

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

Рассмотрим:

class MyClass
{
 public:
  void myFunction(ForwardIterator &i)
  {
    //do some code here
    savedIter = i;
    //do some code here
  }
 private:
  ForwardIterator savedIter;
}

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

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