Почему строковый литерал копируется при назначении const std :: string? - PullRequest
0 голосов
/ 09 ноября 2018

Согласно cppreference.com , когда const std::string создается из входа const char* (например, const std::string("some literal");), копия строки C сохраняется вstd::string.

Я пытаюсь понять, требуется ли (и почему) копия специально для случая, когда входная строка C является строковым литералом.Я думаю, что std::string может просто ссылаться на строковый литерал вместо создания копии, так что следующий код будет создавать "some literal" только один раз.

std::string str1("some literal");
std::string str2("some literal");

Конечно, выполнение копии для CСтроки, которые не являются строковыми литералами, разумны, поскольку позволяют std::string управлять временем жизни данных, на которые оно ссылается.Тем не менее, это не проблема для строковых литералов, потому что они существуют на протяжении всей жизни программы.

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

Итак, есть ли причина, почемукомпилятор не может оптимизировать этот случай, чтобы const std::string s ссылались на const char* s вместо создания копий?В качестве альтернативы, если ссылка cppreference была неправильной, и эта оптимизация на самом деле * реализована некоторыми компиляторами , какие компиляторы поддерживают это?

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

1 Ответ

0 голосов
/ 09 ноября 2018

В вашем примере std::string просто получает указатель, он не может знать, на какую память на самом деле указывает указатель.

Тот факт, что указатель объявлен как указывающий на постоянные данные, не имеет значения. Указатель на неконстантные данные может быть назначен указателю на постоянные данные (создавая доступ только для чтения к другим записываемым данным).

std::string просто не может знать, что данный указатель указывает на строковый литерал. Указатель может так же легко указывать на массив в стеке вызовов, или на блок памяти, выделенный с помощью new, или на память, принадлежащую внешней библиотеке.

В узком строковом литерале нет ничего особенного, это не какой-то магический тип, для которого std::string может настроить его поведение. Это просто обычный const char[], просто тот, чья память настраивается компилятором / компоновщиком. Распадается до const char *.

Таким образом, std::string делает единственную разумную и безопасную вещь, которую он может сделать, учитывая отсутствие информации о происхождении, - делает копию данных.

Это также делает реализацию простой: std::string всегда владеет данными, которые он хранит.

Если вам нужен контейнер в виде строки, который не владеет данными, просто указывает на него, а затем посмотрите на C ++ 17's std::string_view или boost::string view для более ранних компиляторов.

...