Стоит ли сравнивать std :: string с "string" или "string"? - PullRequest
44 голосов
/ 03 июня 2019

Рассмотрим этот фрагмент кода:

bool foo(const std::string& s) {
    return s == "hello"; // comparing against a const char* literal
}

bool bar(const std::string& s) {
    return s == "hello"s; // comparing against a std::string literal
}

На первый взгляд , похоже, что для сравнения с const char* требуется меньше инструкций по сборке 1 , поскольку используетсястроковый литерал приведет к созданию на месте std::string.

Однако, глядя на ссылку operator==(const char*, const std::string&):

Все сравнения выполняются с помощью compare() функции-члена.

Насколько я понимаю, это означает, что нам все равно нужно будет построить std::string, чтобы выполнить сравнение, поэтому я подозреваю, чтонакладные расходы будут такими же в конце (хотя и скрыты при вызове operator==).

( РЕДАКТИРОВАТЬ: как указано в ответах, я забыл о фактечто по факту s.compare(const char*) будет вызываться в foo(), так что, конечно, в этом случае не будет построений на месте )

  • Какое из сравнений мне выбрать?
  • Имеет ли одна версия преимущество перед другой (может быть в определенных ситуациях)?

1 Я знаю, что меньшее количество инструкций по сборке не обязательно означает более быстрый код, но я не хочу вдаваться в микропроцессорность здесь.

Ответы [ 3 ]

65 голосов
/ 03 июня 2019

Ни.

Если вы хотите быть умным, сравните с "string"sv, который возвращает std::string_view.


Хотя сравнение с литералом, подобным "string", не приводит к каким-либо накладным расходам на выделение ресурсов, оно обрабатывается как строка с нулевым символом в конце, со всеми вытекающими из этого недостатками: нет допусков для встроенных нулей, и пользователи должны учитывать нулевой терминатор.

"string"s выполняет распределение, исключая small-string-оптимизация или elision выделения . Кроме того, оператору передается длина литерала, счет не нужно, и он допускает встраивание нулей.

И, наконец, использование "string"sv сочетает в себе преимущества обоих других подходов, избегая их индивидуальных недостатков. Кроме того, std::string_view - намного более простой зверь, чем std::string, особенно если последний использует SSO, как и все современные.


По крайней мере, начиная с C ++ 14 (который обычно разрешал выделение ресурсов), компиляторы могли бы теоретически оптимизировать все варианты до последнего, учитывая достаточную информацию (обычно доступную для примера) и усилия, под как если правило . Мы еще не там, хотя.

13 голосов
/ 03 июня 2019

Нет, compare() не требует построения std::string для const char* операндов.

Вы используете перегрузка # 4 здесь .

Сравнение со строковым литералом - это "бесплатная" версия, которую вы ищете. Создание std::string здесь совершенно не нужно.

9 голосов
/ 03 июня 2019

Насколько я понимаю, это означает, что нам все равно нужно будет построить std::string, чтобы выполнить сравнение, поэтому я подозреваю, что издержки в конце будут такими же (хотя и скрыты при вызове operator==).

Вот где это рассуждение идет не так.std::compare не нужно выделять свой операнд в виде строки с нулевым символом в конце для функции.Согласно одной из перегрузок:

int compare( const CharT* s ) const; // (4)

4) Сравнивает эту строку с последовательностью символов с нулевым символом в конце, начинающейся с символа, на который указывает s, с длиной Traits::length(s).

Хотя выделение или нет - это деталь реализации, не представляется разумным, чтобы сравнение последовательностей делало это.

...