Возвращаясь ссылку на локальную переменную из функции


У меня есть несколько вопросов по возвращению ссылки на локальную переменную из функции:

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
}

Мои вопросы =>

  1. Является ли реализация getA1() правильной? Я чувствую, что это неправильно, так как он возвращает адрес локальной переменной или временной.

  2. Какое из утверждений в main (1,2,3) приведет к неопределенному поведению?

  3. В const A& newA1 = getA1(); гарантирует ли стандарт, что временная привязка к ссылке const не будет уничтожен до тех пор, пока ссылка не выйдет за рамки?

4 34

4 ответа:

1. Является ли getA1() реализация правильной ? Я чувствую, что это неправильно, так как это возвращает адрес локальной переменной или временной.

Единственная версия getAx(), которая является правильной в вашей программе, - это getA3(). Оба других имеют неопределенное поведение, независимо от того, как вы используете их позже.

2. Какое из утверждений в main (1,2,3) приведет к неопределенному поведению ?

В каком-то смысле ни один из них. Для 1 и 2 неопределенное поведение имеет вид результат выполнения органами функций. Для последней строки newA3 должно быть ошибкой компиляции, так как вы не можете привязать временную ссылку к неконстантной ссылке.

3. В const A& newA1 = getA1(); ли стандарт гарантирует, что временная привязка к const ссылка не будет уничтожена до тех пор, пока ссылка не выйдет за пределы области действия?

Нет. Ниже приведен пример этого:

A const & newConstA3 = getA3 ();

Здесь getA3() возвращает временное значение, и время жизни этого временного значения теперь привязано к объекту newConstA3. Другими словами, временное будет существовать до тех пор, пока newConstA3 не выйдет за рамки.

Q1: Да, это проблема, см. ответ на Q2.

Q2: 1 и 2 не определены, поскольку они ссылаются на локальные переменные в стеке getA1 и getA2. Эти переменные выходят за пределы области видимости и больше не доступны, а хуже того, могут быть перезаписаны, поскольку стек постоянно меняется. getA3 работает, так как копия возвращаемого значения создается и возвращается вызывающему объекту.

Q3: нет такой гарантии, чтобы увидеть ответ на Q2.

Я думаю, что главная проблема заключается в том, что вы вообще не возвращаете временные данные, вы должны

return A(5);

Вместо

A a(5);
return a;

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

Я думаю, что это объясняется здесь: временная ссылка на const

Если вы скомпилируете это на 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;

}