Устанавливаются ли указатели на строковые литералы после возвращения функции?

Верен ли указатель, возвращаемый следующей функцией?

const char * bool2str( bool flg )
{
    return flg ? "Yes" : "No";
}

Хорошо работает в Visual С++ и g++. Что говорит об этом стандарт С++?

Ответы

Ответ 1

Время хранения:

2.13.4Обычные строковые литералы и строковые литералы UTF-8 также называются узкими строковыми литералами. Стрелка string literal имеет тип "array of n const char", где n - размер строки, как определено ниже, и имеет статическая продолжительность хранения

читать вместе с 3.7.1

3.7.1.

Все объекты, не имеющие динамической продолжительности хранения, не имеют продолжительности хранения потоков и не локальные имеют статическую продолжительность хранения. Хранение данных объектов должно продолжаться в течение (3.6.2, 3.6.3).

Тип типа:

Приложение C

Подпункт 2.13.4:

Изменить: строковые литералы, сделанные const Тип строкового литерала изменяется от "array of char" до "array of const char". Тип Строковый литерал char16_t изменяется от "array of some-integer-type" до "array of const char16_t". тип строкового литерала char32_t изменяется от "array of some-integer-type" до "array of const char32_- t." Тип широкоформатного литерала изменяется от "array of wchar_t" до "array of const wchar_t."

Обоснование:. Это позволяет избежать ненадлежащей перегруженной функции, которая, возможно, измените его аргумент.

Влияние на оригинальную функцию: Изменить на семантику четко определенной функции. Трудность преобразования: Простая синтаксическая трансформация, поскольку строковые литералы могут быть преобразованы в char *; (4.2). Наиболее распространенные случаи обрабатываются новым, но устаревшим стандартным преобразованием: char * p = "abc";//действителен в C, устарел в С++ char * q = expr? "abc": "de";//допустимо в C, недействительно в С++

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

Динамически выделяется (слово "куча" никогда не используется в контексте области памяти AFAIK в стандартной) памяти требуется вызов функции, который может произойти уже в начале main после размещения статической памяти.

Ответ 2

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

Ответ 3

Этот код действителен и соответствует стандарту.

Строковые литералы хранятся в постоянной памяти, а функция просто получает адрес выбранной строки.

Стандарт С++ (2.13.4) говорит:

Обычный строковый литерал имеет тип "массив n const char" и статический время хранения

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

Ответ 4

Технически Да, это действительно. Строки имеют статическую дюрацию хранилища.

Но это не вся история.

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

Если вы не будете следовать этим соглашениям, вы соберете много опытных разработчиков C, которые ожидали бы этого соглашения. Если вы не выполняете это стандартное ожидание, оно должно быть хорошо документировано в коде.

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

Если вы обеспокоены эффективностью, я думаю, что это ложная проблема.

Если вы хотите, чтобы это для печати через потоки, для этого уже есть стандартное соглашение:

std::cout << std::boolalpha << false << std::endl;
std::cout << std::boolalpha << true  << std::endl;