Pre-C ++ 11 ответ
Вы правы в том, что в стандарте не указано, какой должна быть сложность list :: size (), однако рекомендуется, чтобы он "имел постоянную сложность" (Примечание A в таблице 65).
Вот интересная статья Говарда Хиннанта , которая объясняет, почему некоторые люди думают, что list :: size () должен иметь сложность O (N) (в основном потому, что они считают, что O (1) list :: size ( ) делает list :: splice () сложностью O (N)) и почему O (1) list :: size () будет хорошей идеей (по мнению автора):
Я думаю, что основные пункты в статье:
- есть несколько ситуаций, когда ведение внутреннего счета, поэтому
list::size()
может быть O (1), заставляет операцию сращивания стать линейной
- вероятно, существует гораздо больше ситуаций, когда кто-то может не знать о негативных эффектах, которые могут произойти, потому что они вызывают O (N)
size()
(например, его единственный пример, где list::size()
вызывается при удержании блокировки).
- что вместо разрешения
size()
быть O (N), в интересах "наименьшего удивления", стандарт должен требовать любого контейнера, который реализует size()
для его реализации в виде O (1). Если контейнер не может этого сделать, он вообще не должен реализовывать size()
. В этом случае пользователь контейнера будет уведомлен о том, что size()
недоступен, и если он все еще хочет или должен получить количество элементов в контейнере, он все еще может использовать container::distance( begin(), end())
, чтобы получить это значение - но они будет полностью знать, что это операция O (N).
Я думаю, что склонен согласиться с большей частью его рассуждений. Однако мне не нравится его предложенное дополнение к перегрузкам splice()
. Необходимость передать n
, которое должно быть равно distance( first, last)
, чтобы получить правильное поведение, похоже на рецепт для трудно диагностируемых ошибок.
Я не уверен, что нужно или можно сделать, чтобы двигаться вперед, так как любое изменение окажет значительное влияние на существующий код. Но в нынешнем виде я думаю, что существующий код уже подвержен влиянию - поведение может значительно отличаться от одной реализации к другой для чего-то, что должно быть четко определено. Возможно, один комментарий о том, что размер «кэширован» и помечен как известный / неизвестный, может работать хорошо - вы получаете амортизированное поведение O (1) - единственный раз, когда вы получаете поведение O (N), это когда список изменяется некоторыми операциями splice () , Хорошая вещь об этом - то, что это может быть сделано разработчиками сегодня без изменения стандарта (если я что-то упускаю).
Насколько я знаю, C ++ 0x ничего не меняет в этой области.