Что такое fast string.empty() или string.size() == 0?
Недавно во время обсуждения меня попросил программист внести некоторые изменения в код. У меня было что-то вроде:
if( mystring.size() == 0)
// do something
else
// do something else
Обсуждалось использование mystring.empty()
для проверки, является ли строка пустой. Теперь я согласен, что можно утверждать, что string.empty()
более подробный и читаемый код, но есть ли какие-либо преимущества в производительности?
Я немного поработал и нашел эти 2 ответа, относящиеся к моему вопросу:
Оба ответа подтверждают мое утверждение о том, что string.empty()
является более читаемым и не дает каких-либо преимуществ по производительности, по сравнению с string.size() == 0
.
Я все еще хочу быть уверенным, если есть какие-либо реализации string
, которые сохраняют внутренний логический флаг для проверки, является ли строка пустой или нет?
Или существуют другие способы использования некоторых реализаций, которые аннулируют мое требование?
Ответы
Ответ 1
Стандарт определяет empty()
следующим образом:
bool empty() const noexcept;
Возвращает: size() == 0.
Вам будет трудно найти что-то, что этого не сделает, и любая разница в производительности будет незначительной из-за того, что оба являются операциями с постоянным временем. Я бы ожидал, что оба будут компилироваться с той же самой сборкой в любой разумной реализации.
Тем не менее, empty()
ясен и ясен. Вы должны предпочесть его для size() == 0
(или !size()
) для удобства чтения.
Ответ 2
Теперь, это довольно тривиальный вопрос, но я постараюсь полностью его осветить, поэтому любые аргументы, которые ставят коллеги, вряд ли заставят вас врасплох....
Как обычно, если профилирование доказало, что вам действительно нужно было позаботиться, измерьте: может быть разница (см. ниже). Но в общей ситуации обзора кода для недоказанно-проблемно-медленного кода остаются нерешенными проблемы:
-
в некоторых других контейнерах (например, списки С++ 03, но не С++ 11), size()
был менее эффективным, чем empty()
, что привело к некоторым советам по кодированию, чтобы предпочесть empty()
над size()
в общем, так, чтобы, если кому-то понадобилось позже переключить контейнер (или обобщить обработку в шаблон, где тип контейнера может меняться), для сохранения эффективности изменений не требуется.
-
отражает ли более естественный способ представления теста? - не только то, о чем вы сначала думали, либо size()
, потому что вы не привыкли использовать empty()
, но когда вы на 100% сосредоточены на логике кода окружения, size()
или empty()
лучше вписаться? Например, возможно, потому, что это один из нескольких тестов size()
, и вам нравится иметь согласованность, или потому, что вы реализуете известный алгоритм или формулу, которые традиционно выражаются в терминах размера: согласование может уменьшить умственный шум/усилие при проверке реализация против формулы.
В большинстве случаев вышеприведенные факторы несущественны, а проблема в обзоре кода - это пустая трата времени.
Возможная разница в производительности
В то время как Стандарт требует функциональной эквивалентности, некоторые реализации могут реализовывать их по-разному, хотя я боролся и до сих пор не смог описать особенно правдоподобную причину этого.
С++ 11 имеет больше ограничений, чем С++ 03, над поведением других функций, которые влияют на выбор реализации: data()
должен быть завершен NUL (используется только как c_str()
), [size()]
теперь является допустимым индексом и должен вернуть ссылку на символ NUL. По разным тонким причинам эти ограничения делают еще более вероятным, что empty()
будет не быстрее, чем size()
.
В любом случае - измерьте, если вам нужно.