c ++ возвращает константную ссылку на локальную переменную - PullRequest
0 голосов
/ 13 января 2010

возможно / нормально вернуть константную ссылку, даже если значение, которое возвращает функция, является локальной переменной этой функции? я знаю, что локальные значения больше не действительны после того, как функция вернется - но что, если функция встроена, а возвращаемое значение используется только в области действия вызывающих программ? тогда локальные значения функции должны быть включены в стек стека вызывающих программ, нет?

Ответы [ 7 ]

8 голосов
/ 13 января 2010

Не рассчитывай на это. Даже если это работает на 1 компиляторе, это не стандартное поддерживаемое поведение и, скорее всего, нарушит другие.

6 голосов
/ 13 января 2010

Нет, все не в порядке. Локальные переменные объявляются в стеке, и стек продолжает меняться между вызовами методов. Кроме того, объекты, которые выходят из области видимости, уничтожаются. Всегда возвращайте копию локальной переменной.

Рассмотрим этот код:

#include <iostream>
using namespace std;

class MyClass
{
public:
  MyClass() { cout << "ctor" << endl; }
  ~MyClass() { cout << "dtor" << endl; }
  MyClass(const MyClass& r) { cout << "copy" << endl; }
};

const MyClass& Test()
{
  MyClass m;
  return m;
}

int main()
{
  cout << "before Test" << endl;
  MyClass m = Test();
  cout << "after Test" << endl;
}

Это распечатает:

before Test
ctor
dtor
copy
after Test
dtor

Объект, который вы пытаетесь скопировать, уже вызвал деструктор и может находиться в недопустимом состоянии.

4 голосов
/ 13 января 2010

inline - это , а не гарантия - это предложение . Даже если вы используете трюки для форсирования, вы никогда не будете уверены в результате, особенно если вы хотите оставаться переносимым.

Следовательно, не делают это.

1 голос
/ 13 января 2010

Как уже отмечали другие, это опасно. Это также не требуется, если ваш компилятор поддерживает NRVO (оптимизацию именованных возвращаемых значений), а ваша функция использует и возвращает локальную переменную, которую вы хотели бы вернуть с помощью ref, довольно простым способом.

NRVO позволяет компилятору избегать создания копии при определенных условиях - обычно это основная причина, чтобы избежать возврата объектов по значению. VC ++ 8 поддерживает это (различие в предыдущих ревизиях), и это делает довольно много различий в часто используемом коде.

1 голос
/ 13 января 2010

Это вызывает неопределенное поведение.

  • Нет способа заставить компилятор встроить функцию. inline это просто предложение - так же __forceinline
  • Даже если бы вы могли гарантировать, что функция будет встроенной, деструктор для рассматриваемой переменной все равно будет выполнен, оставив вам ссылку на мертвый объект.
  • И самое важное - Концепция стека в C ++ ограничена областью, а не функцией.

#include <iostream>
int main()
{
  {
    int a = 5;
    std::cout << std::hex << "0x" << &a << std::endl;
  }
  {
    int b = 10;
    std::cout << std::hex << "0x" << &b << std::endl;
  }
}

Мой компилятор помещает 'a' и 'b' в разные адреса памяти. За исключением случаев, когда я включаю оптимизации. Вы вполне можете решить, что это оптимизация для повторного использования памяти, которую ранее занимал ваш объект.

Есть ли какая-то специфическая проблема, которую вы пытаетесь решить здесь? Существуют и другие способы уменьшения количества создаваемых временных объектов, если вас это беспокоит.

0 голосов
/ 13 января 2010

Ключевое слово inline не гарантирует, что функция действительно встроена. Не делай этого.

0 голосов
/ 13 января 2010

Значение выпадает из области видимости, когда вызываемый объект выпадает из области видимости. Так что нет, это ушло.

Но если вы хотите довольно уродливое решение (и красный флаг, предупреждающий вас о том, что вашему дизайну может потребоваться рефакторинг), вы можете сделать что-то вроде этого:

const MyObj& GetObj()
{
  static const MyObj obj_;
  return obj_;
}

... но это решение, если оно чревато опасностью, особенно если объект является изменяемым или делает что-то нетривиальное в многопоточной среде.

...