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
CleverLibre Social

CleverLibre Social is an inclusive social instance for open discussion, learning, and community.
All cultures welcome.
Hate speech and harassment strictly forbidden.