По завершении работы функции все хранилища ее локальных объектов освобождаются (см. раздел 6.1.1). Поэтому после завершения работы функции ссылки на ее локальные объекты ссылаются на несуществующие объекты.
//
const string &manip() {
string ret;
//
if (!ret.empty())
return ret; //
else
return "Empty"; //
}
Эта функция приведет к отказу во время выполнения, поскольку она возвращает ссылку на локальный объект. Когда функция завершит работу, область памяти, которую занимала переменная ret
, будет освобождена. Возвращаемое значение будет ссылаться на ту область памяти, которая уже недоступна.
Оба оператора return
возвращают здесь неопределенное значение — неизвестно, что будет, попробуй мы использовать значение, возвращенное функцией manip()
. В первом операторе return
очевидно, что функция пытается вернуть ссылку на локальный объект. Во втором случае строковый литерал преобразуется в локальный временный объект класса string
. Этот объект, как и строка s
, является локальным объектом функции manip()
. Область памяти, в которой располагается временный объект, освобождается по завершении функции. Оба оператора return
возвращают ссылки на области памяти, которые больше недоступны.
Возвращать указатель на локальный объект нельзя по тем же причинам. По завершении функции локальные объекты освобождаются, и указатель указывает на несуществующий объект.
Подобно любому оператору, оператор вызова обладает порядком (ассоциативностью) и приоритетом (см. раздел 4.1.2). У оператора вызова тот же приоритет, что и у операторов "точка" и "стрелка" (см. раздел 4.6). Как и эти операторы, оператор вызова имеет левосторонний порядок. В результате, если функция возвращает указатель, ссылку или объект типа класса, результат вызова можно использовать для обращения к члену полученного объекта.
Например, размер более короткой строки можно определить следующим образом:
//
auto sz = shorterString(s1, s2).size();
Поскольку эти операторы имеют левосторонний порядок, результат вызова функции shorterString()
будет левым операндом точечного оператора. Этот оператор выбирает метод size()
объекта строки. Этот метод становится левым операндом второго оператора вызова.
Является ли вызов функции l-значением (см. раздел 4.1.1), зависит от типа возвращаемого значения функции. Вызовы функции, возвращающей ссылку, являются l-значением; другие типы возвращаемого значения являются r-значениями. Вызов функции, возвращающей ссылку, применяется таким же способом, как и любое другое l-значение. В частности, можно осуществлять присвоение результату вызова функции, возвращающей ссылку на неконстанту:
char &get_val(string &str, string::size_type ix) {
return str[ix]; //
}
int main() {
string s("a value");
cout << s << endl; //
get_val(s, 0) = 'A'; //
cout << s << endl; //
return 0;
}
Может быть несколько странно видеть вызов функции слева от оператора присвоения. Однако в этом нет ничего необычного. Возвращаемое значение — ссылка, поэтому вызов — это l-значение, а любое l-значение может быть левым операндом оператора присвоения.
Если тип возвращаемого значения является ссылкой на константу, то (как обычно) присвоение результату вызова невозможно:
shorterString("hi", "bye") = "X"; //
//