Атрибут функции C ++ для указания времени жизни возвращаемого значения совпадает с аргументом - PullRequest
0 голосов
/ 07 февраля 2019

Этот код имеет неопределенное поведение:

#include <string>

std::string make_str(const char* s)
{
    return s;
}

const char* get_str(const std::string& s)
{
    return s.c_str();
}

const char* bad()
{
    return get_str(make_str("hello"));
}

Плохая функция создает временный std :: string и возвращает указатель на свои данные, который становится недействительным, как только функция вернулась.

GCC 5+ ловит это («функция возвращает адрес локальной переменной»), но только если компилируется с -O3.При более типичных уровнях оптимизации, включая -O2, GCC компилирует его без жалоб, даже с -Wall -Wextra.Clang никогда не поймает его, если вы не используете экспериментальную функцию -Wlifetime.

Мой вопрос: Можем ли мы явно сообщить компилятору о таких зависимостях времени жизни, например, используя атрибут?Например, я хотел бы иметь возможность сделать это:

[[lifetime-depends : s]] // hypothetical syntax
const char* get_str(const std::string& s);

Или, может быть, так:

const char* get_str(const std::string& s)
  __attribute__((lifetime-depends(0))); // hypothetical syntax

Я приму ответ, который работает с любым официальным выпуском GCC илиЗвон, но предпочитаю GCC 6.1 с C ++ 14.Эксперимент Кланга -Wlifetime не является ответом, потому что я хочу быть явным, а не полагаться на эвристику (которая, по-видимому, в любом случае не будет работать на нескольких единицах перевода).

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

1 Ответ

0 голосов
/ 07 февраля 2019

Ответ, основанный на мнении, который не дает ответа, но ставит под сомнение идею, стоящую за этим вопросом (и был слишком большим текстом для комментария):

ИМХО, что подразумевало бы довольно большую надежность для понимания компилятором, чтобы пойматьошибки пользователя, потому что это код, который вы опубликовали, ошибка.Стандарт уже описывает, как обрабатывать временные промежутки времени, и рассматривает возможность продления срока службы в тех случаях, когда эталон все еще используется (см. Черновик n4713 , например, п. 15.2, пункт 5).Тем не менее, ваш опубликованный пример - другой случай ...

Кроме того, хотя в документе p1179r0 (комментарий от PW) действительно есть идея для указателей на объекты, хранящиеся в стеке это не помогает с объектами в куче.И как это должно быть?Возврат указателя на символ (или любой тип) не является ошибкой ... возврат указателя на массив, который больше не существует, есть.Откуда ему знать, что c_str () возвращает указатель на массив временного объекта, который удаляет в своем деструкторе (вроде как, не так ли?)?Как узнать, уничтожен ли массив?Глядя в деструктор, если удаление сделано?Что делать, если деструктор не удаляет?Предупредить о деструкторе следует удалить?Что если new был новым местом размещения?Что если .... заводской шаблон ...?Что если создать указатели для умного указателя (например, shared_ptr) ...?Что если еще 200 очков ... Управление временем жизни в куче, в основном, приведет к сбору мусора.

Вы получите предупреждение function returns address of local variable [-Wreturn-local-addr], которое, я думаю, не имеет ничего общего с вашим кодом, ноболее "несчастный случай", вызванный оптимизацией короткой строки.Оптимизированная система единого входа std::string возвращает указатель на локальный объект, как говорится в сообщении ... Простой тест, сделайте вашу строку длиннее 16 символов, предупреждение исчезнет ...

...