Size() Vs empty() в векторе - почему пустым() является предпочтительным?
При отладке чего-то я увидел реализацию STL vector:: empty():
bool empty() const
{return (size() == 0); }
Я считаю, что всякий раз, когда мы исследуем пустоту вектора, всегда рекомендуется использовать пустой над size(). Но, видя эту реализацию, я задаюсь вопросом, в чем преимущество этого? Вместо этого есть накладные расходы на вызов функции при вызове пустого, поскольку он внутренне вызывает size() == 0.
Я думал, что empty() может оказаться полезным в случае списка, поскольку size() не гарантирует постоянное время в списке. Чтобы проверить мое предположение, я проверил реализацию списка и, что удивительно, нашел ту же реализацию в списке,
return (size() == 0);
Я немного запутался. Если пустым внутренне используется size(), то почему мы предпочитаем пустую над size()?
Ответы
Ответ 1
Вам нужно будет написать условие каждый раз, когда вы используете size()
. Удобно использовать empty()
. Это, конечно, при условии, что вы не переключаете контейнеры. Как указывали другие, до внедрения использовать size()
в empty()
или нет. Однако стандарт гарантирует, что: empty()
- операция постоянной времени для всех
стандартные контейнеры.
Ответ 2
Потому что если вы перейдете из std::vector в std:: list или другой контейнер, это может быть другим.
Например, некоторые реализации std::list::size
принимают O(n)
, а не O(1)
.
Ответ 3
Ну, как вы говорите, это просто деталь реализации. std::list
может быть реализован либо с сохраненным размером (постоянным временем size()
, но с линейным временем splice()
), либо без (постоянное время splice()
, но линейное время size()
)). Выбирая использовать empty()
, вы избегаете делать ставки на детали реализации, когда вам не нужно знать размер.
Ответ 4
Следуя стандарту, пустая() должна быть предпочтительной, так как она имеет постоянную временную сложность независимо от типа контейнера.
В стандарте С++ 03, глава 23.1, таблица 65: Требования к контейнеру
Operation: empty()
Return_type: convertible to bool
Semantics: equivalent to size()==0
Complexity: constant
Кажется, что в вашей реализации STL они воспринимали семантику как реальную реализацию, игнорируя требования сложности, или size() - постоянное время в реализации (сохраненное поле).
Если size() не является постоянным временем, обратитесь к поставщику по адресу std:: list < > :: empty(), не выполнив стандартные требования к контейнеру.
Ответ 5
1st, используя функцию с именем empty()
, когда вы хотите знать, что что-то пусто, делает код более читаемым и означает, что вам не нужно беспокоиться о деталях реализации. Это также означает, что ваш код легче адаптировать к другим типам контейнеров с другими характеристиками.
2nd, это только одна реализация STL.
Мой GNU С++ выглядит так:
bool
empty() const
{ return begin() == end(); }
Это в конечном итоге приведет к сопоставлению указателей, в то время как использование size() приведет к вычитанию (в этой реализации).
В-третьих, это вряд ли приведет к накладным расходам дополнительного вызова функции, поскольку empty()
-функция, вероятно, включена (в обеих реализациях).
Ответ 6
empty() имеет O (1) реализации для ВСЕХ контейнерных классов. size() может предоставлять только O (n) реализации для некоторых контейнеров; поэтому пустая() является предпочтительной.
Ответ 7
В дополнение к причинам, приведенным выше, это также возможно более ясное, чем foo.size() == 0 и/или! foo.size()
Ответ 8
Помимо точки удобочитаемости, которая является очень достоверной, то, что вы испытали, - это просто артефакты одной конкретной реализации, а не единственно возможная.
То есть, нет никаких оснований или требований, чтобы empty() реализовывался в терминах size() как в случае вектора, так и в списке, или в деле любого другого контейнера. Если есть более эффективные альтернативы, они должны использоваться, если автор библиотеки не являются некомпетентными или более разумно ленивыми.
Что касается списка и O (1) -ness size() или его отсутствия, вы должны учитывать, что этот список может реализовать либо size(), либо O (1), либо splice(), но не оба (думать о причине - интересное упражнение). Таким образом, в вашем случае проверенная библиотека может иметь размер() как O (1) (в этом случае splice() будет O (n)) и, следовательно, может реализовать empty() с точки зрения размера(), не жертвуя производительностью, иначе это будет очень плохая библиотека.
Ответ 9
Предпочитаете использовать use empty(), чем size(), потому что каждый контейнер может реализовать пустую() реализацию по-другому, чтобы получить операцию с постоянным временем.
Пример:
вектор реализуется как: bool empty() const {//проверить, является ли последовательность пустой return (size() == 0); }
список реализуется как:
bool empty() const
{ // test if sequence is empty
return (_Mysize == 0);
}