Возвращение константной ссылки на локальную переменную из функции
У меня есть несколько вопросов по возвращению ссылки на локальную переменную из функции:
class A {
public:
A(int xx)
: x(xx)
{
printf("A::A()\n");
}
};
const A& getA1()
{
A a(5);
return a;
}
A& getA2()
{
A a(5);
return a;
}
A getA3()
{
A a(5);
return a;
}
int main()
{
const A& newA1 = getA1(); //1
A& newA2 = getA2(); //2
A& newA3 = getA3(); //3
}
Мои вопросы =>
-
Правильна ли реализация getA1()
? Я чувствую, что это неверно, так как он возвращает адрес локальной переменной или временный.
-
Какое из утверждений в main
(1,2,3) приведет к неопределенному поведению?
-
В const A& newA1 = getA1();
гарантирует ли стандарт, что временная привязка константной ссылкой не будет уничтожена, пока ссылка не выйдет из области видимости?
Ответы
Ответ 1
1. Правильно ли реализация getA1()
? Я считаю, что это неверно, поскольку он возвращает адрес локальной переменной или временный.
Единственная версия getAx()
, которая правильна в вашей программе, - getA3()
. Оба других имеют поведение undefined независимо от того, как вы их используете позже.
2. Какое из утверждений в главном (1,2,3) приведет к поведению undefined?
В некотором смысле ни один из них. Для 1 и 2 поведение undefined является результатом тел функций. Для последней строки newA3
должна быть компиляционной ошибкой, так как вы не можете привязать временную ссылку к не const.
3. В const A& newA1 = getA1();
стандарт гарантирует, что временная привязка к const
ссылка не будет уничтожена до тех пор, пока ссылка не выйдет из области видимости?
Нет. Ниже приведен пример:
A const & newConstA3 = getA3 ();
Здесь getA3()
возвращает временное, а время жизни этого временного объекта привязано к объекту newConstA3
. Другими словами, временное существо будет существовать до тех пор, пока newConstA3
не выйдет из области видимости.
Ответ 2
Q1: Да, это проблема, см. ответ на Q2.
Q2: 1 и 2 undefined, поскольку они относятся к локальным переменным в стеке getA1 и getA2. Эти переменные выходят за рамки и больше не доступны, и хуже может быть перезаписано, поскольку стек постоянно меняется. getA3 работает, поскольку копия возвращаемого значения создается и возвращается вызывающему.
Q3: Нет такой гарантии, чтобы видеть ответ на Q2.
Ответ 3
Я думаю, главная проблема заключается в том, что вы не возвращаете временные рамки вообще, вы должны
return A(5);
а не
A a(5);
return a;
В противном случае вы возвращаете адрес локальной переменной, а не временный. И временная ссылка на const ссылается только на временные.
Я думаю, его объяснение здесь:
временная ссылка на const
Ответ 4
Если вы скомпилируете это на VC6, вы получите это предупреждение
****** Предупреждение о компиляторе (уровень 1) C4172
возвращающий адрес локальной переменной или временной
Функция возвращает адрес локальной переменной или временного объекта. Локальные переменные и временные объекты уничтожаются при возврате функции, поэтому возвращаемый адрес недействителен. ******
Во время тестирования для этой проблемы я нашел интересную вещь (данный код работает в VC6):
class MyClass
{
public:
MyClass()
{
objID=++cntr;
}
MyClass& myFunc()
{
MyClass obj;
return obj;
}
int objID;
static int cntr;
};
int MyClass::cntr;
main()
{
MyClass tseadf;
cout<<(tseadf.myFunc()).objID<<endl;
}