Follow

Давно хотел в плюсах посмотреть на проблему при возвращении const'ной ссылки из метода/функции в C++. Тема старая, но всё никак руки не доходили.
Есть следующий код (очередной искусственный пример для демонстрационных целей):

<iostream>
<string>

<cstdlib>

const std::string& takeString(int value, const std::string& str1, const std::string& str2, const std::string& str3)
{
if (value < 0)
{
return str1;
}
if (value > 0)
{
return str2;
}
return str3;
}

int main(int argc, char* argv[])
{
if (argc != 2)
{
std::exit(1);
}

int value = std::atoi(argv[1]);
std::string s1 = "one";
std::string s2 = "two";
const std::string& s = takeString(value, s1, s2, "three");
std::cout << "s: " << s << "\n";

return 0;
}

Компилируем и выполняем с разными опциями:
$ ./example -10
s: one

$ ./example 10
s: two

Если же вызвать с опцией 0:
$ ./example 0

результат будет неопределён (конкретно у меня был выведен "мусор" на экран). Если скомпилировать программу с адрес санитайзером (-fsanitize=address), то при вызове example с опцией 0 получим следующую ошибку:
ERROR: AddressSanitizer: stack-use-after-scope

В чём суть проблемы? При внимательном рассмотрении кода видно, что вызов функции takeString на самом деле будет следующим:

const std::string& s = takeString(value, s1, s2, std::string("three"));

т.е. при передаче третьим аргуметом литерала "three" будет сконструирован временный объект типа std::string, который разрушится перед выходом из функции takeString, что логично. Продление времени жизни объекта за счет const std::string& s здесь не будет выполняться.
В результате, когда функция takeString возвращает str3, будет получена висячая ссылка. В случае, когда вызов takeString возвращает s1 или s2 никаких проблем нет, т.к. они разрушатся при выходе из main, их можно спокойно использовать после вызова takeString (в std::cout).

Какой вывод нужно сделать? Не нужно возвращать из функции/метода по константной ссылке параметр типа константная ссылка, да и любой другой временный объект, например:

const int& badFunction()
{
int value = 42;
return value;
}

Правда тут мне компилятор выдал предупреждение:
warning: reference to stack memory associated with local variable 'value' returned [-Wreturn-stack-address]

Sign in to participate in the conversation
Qoto Mastodon

QOTO: Question Others to Teach Ourselves
An inclusive, Academic Freedom, instance
All cultures welcome.
Hate speech and harassment strictly forbidden.