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 ничего не меняет в этой области.
person
Michael Burr
schedule
23.10.2008