Преимущества использования пользовательского литерала для строк вместо строкового литерала


тема строк в документации SO обычно говорила в разделе "Примечания":

начиная с C++14, вместо использования "foo", рекомендуется использовать "foo"s, а s - строковый литерал, который преобразует const char *"foo" до std::string"foo".

единственное преимущество, которое я вижу через

std::string str = "foo"s;

вместо

std::string str = "foo";

это в первом случае компилятор может выполнить copy-elision (я думаю), что будет быстрее, чем вызов конструктора во втором случае.

тем не менее, это (пока) не гарантировано, поэтому первый может также вызвать конструктор, конструктор копирования.

игнорируя случаи, когда это требуются использовать std::string литералы, такие как

std::string str = "Hello "s + "World!"s;

есть ли какая-либо польза от использования std::string литералы вместо const char[] литералы?

4 51

4 ответа:

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

auto str = "Foo"s;

и так, str будет подлинной std::string, а не const char*. Поэтому он позволяет вам решать, когда и что делать.

это также важно для автоматического вычета типа возврата:

[]() {return "Foo"s;}

или любая форма типа дедукции, действительно:

template<typename T>
void foo(T &&t) {...}

foo("Foo"s);

единственное преимущество, которое я вижу, используя [...] вместо [...] есть что в первом случае компилятор может выполнить copy-elision (я думаю), что было бы быстрее, чем вызов конструктора во втором случае.

Copy-elision не быстрее, чем вызов конструктора. В любом случае, вы вызываете один из конструкторов объекта. Вопрос в том какой:

std::string str = "foo";

это вызовет вызов конструктора std::string что происходит const char*. Но так как std::string, чтобы скопировать строку в свой собственный хранение, он должен получить длину строки, чтобы сделать это. И поскольку он не знает длину, этот конструктор вынужден использовать strlen чтобы получить его (технически, char_traits<char>::length, но это, вероятно, не будет намного быстрее).

в отличие от этого:

std::string str = "foo"s;

это будет использовать шаблон UDL, который имеет этот прототип:

string operator "" s(const char* str, size_t len);

видеть,компилятор знает длину строкового литерала. Таким образом, код UDL передается указатель на строку и a размер. И таким образом, он может вызвать std::string конструктор, который принимает const char*и a size_t. Поэтому нет необходимости вычислять длину строки.

совет, о котором идет речь, не для вас, чтобы обойти и конвертировать каждый использование литерала в s версия. Если вы в порядке с ограничениями массива chars, используйте его. Совет заключается в том, что, если вы собираетесь хранить этот литерал в std::string, лучше всего сделать это, пока это все еще буквальный и не туманный const char*.

совет использовать "blah"s не имеет ничего общего с эффективностью и все связано с корректностью для начинающего кода.

новички C++, которые не имеют фона в C, как правило, предполагают, что "blah" приводит к объекту некоторого разумного строкового типа. Например, чтобы можно было писать такие вещи, как "blah" + 42, который работает на многих языках сценариев. С "blah" + 42 в C++, однако, один просто вызывает неопределенное поведение, обращаясь за пределы конца массива символов.

но если этот строковый литерал записывается как "blah"s тогда вместо этого появляется ошибка компиляции, что гораздо предпочтительнее.

кроме того, UDL делает его легче иметь в строке

std::string s = "foobar"s; // s contains a  in its middle.
std::string s2 = "foobar"; // equivalent to "foo"s
  1. использование строкового литерала C++ означает, что нам не нужно вызывать strlen для вычисления длины. Компилятор уже знает это.
  2. может разрешить имплеметации библиотек, где строковые данные указывают на память в глобальном пространстве, используя литералы C, всегда должны заставлять копию данных кучи памяти при построении.