Эффективно ли неявное построение const std :: string из const char *? - PullRequest
2 голосов
/ 05 мая 2020

Как и многие люди, я имею привычку писать новые строковые функции как функции от const std::string &. Преимущества заключаются в эффективности (вы можете передавать существующие объекты std::string без накладных расходов на копирование / перемещение) и гибкости / читаемости (если все, что у вас есть, это const char *, вы можете просто передать его, и конструкция будет выполнена неявно, без загромождения. ваш код с явной конструкцией std::string):

#include <string>
#include <iostream>
unsigned int LengthOfStringlikeObject(const std::string & s)
{
    return s.length();
}
int main(int argc, const char * argv[])
{
    unsigned int n = LengthOfStringlikeObject(argv[0]);
    std::cout << "'" << argv[0] << "' has " << n << " characters\n";
}

Моя цель - написать эффективный кросс-платформенный код, который может эффективно обрабатывать длинные строки. У меня вопрос, что происходит во время неявной конструкции? Есть ли гарантии, что строка не будет скопирована? Мне кажется, что, поскольку все const, в копировании нет необходимости - все, что нужно - это тонкая оболочка STL вокруг существующего указателя, но я не уверен, насколько зависит от компилятора и платформы, я должен ожидать, что такое поведение будет . Будет ли безопаснее всегда явно писать две версии функции, одну для const std::string & и одну для const char *?

Ответы [ 3 ]

2 голосов
/ 05 мая 2020

Если вы передадите const char* чему-то, что принимает std::string, ссылку или нет, будет создана строка. Компилятор может даже пожаловаться, если вы отправите его по ссылке с предупреждением о наличии неявного временного объекта.

Теперь это может быть оптимизировано компилятором, а также некоторые реализации не будут выделять память для небольших строк. Компилятор также может внутренне оптимизировать его для использования C ++ 17 string_view. По сути, это зависит от того, что вы сделаете со строкой в ​​своем коде. Если вы используете только постоянные функции-члены, умный компилятор может оптимизировать.

Но это зависит от реализации и находится вне вашего контроля. Вы можете явно использовать std::string_view, если хотите взять на себя управление.

1 голос
/ 06 мая 2020

Если вы не хотите копировать, тогда string_view - это то, что вам нужно.

Однако с этим преимуществом возникают проблемы. В частности, вы должны убедиться, что передаваемое вами хранилище прослужит «достаточно долго».

Для строковых литералов это не проблема. Для argv[0] это почти наверняка не проблема. Для произвольных последовательностей символов вам нужно подумать о них.

, но вы можете написать:

unsigned int LengthOfStringlikeObject(std::string_view sv)
{
    return sv.length();
}

и вызвать его с помощью string или const char * , и все будет хорошо.

1 голос
/ 06 мая 2020

Мне кажется, что, поскольку все является константой, копирование не требуется - тонкая оболочка STL вокруг существующего указателя - это все, что нужно

Я не думаю, что это предположение верный. Тот факт, что у вас есть указатель на const, не означает, что базовое значение не может измениться. Это только означает, что значение не может быть изменено с помощью этого указателя . Указатель может указывать на неконстантное хранилище, которое может измениться в любой момент.

Из-за этого библиотека должна делать свою собственную копию (для обеспечения «правильного» наблюдаемого поведения строки). Беглый обзор libstdc ++ показывает, что он всегда делает копию. Конструкция из char* не является встроенной, поэтому ее нельзя оптимизировать без c связывания и LTO.

Хотя в чрезвычайно тривиальных статически связанных программах можно было бы оптимизировать копию с помощью LTO (я не возможность воспроизвести это), я думаю, что в целом эта оптимизация маловероятна (особенно с учетом правил псевдонима для char*). g ++ даже не выполняет эту оптимизацию для строкового литерала.

...