Must size() == end() - begin()? А как насчет трансляции?
Из того, что я понимаю, целью size_type
и difference_type
является not просто знак - он также должен был адресовать, например. сегментированные архитектуры и т.д., где они могут быть разных размеров.
В этом контексте, если у меня есть контейнер с итераторами с произвольным доступом, безопасно ли мне выполнять static_cast
между его значениями difference_type
и size_type
по желанию, исходя из того, что end() - begin()
должен всегда быть равным size()
, когда он ливается?
(Например, пример использования - создать контейнер, размер которого равен количеству элементов между двумя итераторами, или наоборот: скопировать контейнер определенного размера в диапазон, ограниченный итераторами.)
Все, что я должен соблюдать перед литьем (например, потеря данных)?
Ответы
Ответ 1
Здесь, что С++ 11 должен сказать по-разному:
§ 23.2.1
Expression: difference_type
Return Type: signed integer type
Operational Semantics: -
Assertion/note, pre-/post-condition: is identical to the difference type of iterator and const_iterator
Complexity: compile-time
Expression: size_type
Return Type: unsigned integer type
Operational Semantics: -
Assertion/note, pre-/post-condition: size_type can represent any non-negative value of difference_type
Complexity: compile-time
Expression: size()
Return Type: size_type
Operational Semantics: distance(begin(),end())
Assertion/note, pre-/post-condition: -
Complexity: constant
Убедитесь, что size()
эквивалентен end() - begin()
:
§ 24.4.4/4
distance():
Effects: If InputIterator meets the requirements of random access iterator,
returns (last - first); otherwise, returns the number of increments needed
to get from first to last
Так как ваш контейнер имеет итераторы с произвольным доступом, это верно. Это что. Как вы можете видеть в первом окне,
size_type can represent any non-negative value of difference_type
Из этого мы имеем, что приведение от difference_type
до size_type
должно быть справедливым для всех неотрицательных значений.
Ответ 2
Я не думаю, что это всегда безопасно. Эта историческая проблема существовала с момента первой спецификации языка C, где ptrdiff_t
не гарантировало охват всего положительного диапазона size_t
. По понятным причинам этот вопрос переносится на спецификацию std::vector
.
Со стандартными контейнерами С++ гарантируется, что size_type
охватывает неотрицательный диапазон difference_type
, но обратное покрытие не гарантируется.
Однако связь между size()
и end() - begin()
для стандартного контейнера может быть гарантирована другими способами. Реализация может налагать свои собственные ограничения на максимальный размер контейнера, который открывается через функцию container::max_size()
. Он может искусственно ограничивать максимальный размер, чтобы убедиться, что вычитание никогда не переполняется.
P.S. Я бы сказал, что причиной существования difference_type
является только знак и ничего больше. Чтобы быть полностью "безопасным" difference_type
, должно быть на 1 бит больше, чем size_type
. Это часто бывает трудно реализовать на практике, поэтому он не требуется по языковой спецификации.