С++ Возвращение ссылки на временные

Возможный дубликат:
предупреждение: возврат ссылки на временный

Я получаю сообщение об ошибке "возвращение ссылки на временный" во второй строке ниже.

class Object : public std::map <ExString, AnotherObject> const {
public:
const AnotherObject& Find (const ExString& string ) const {
  Object::const_iterator it = find (string);
  if (it == this->end()) { return AnotherObject() };
  return ( it->second );
}
}

Мой класс реализует std:: map.

Я новичок в С++, поэтому я предполагаю, что это просто синтаксическая ошибка. Любая помощь?

Ответ 1

Если ваша функция выглядит так:

AnotherObject& getAnotherObject()
{

    . . .

    Object::const_iterator it = find ("lang");
    if (it == this->end()) { return AnotherObject() };

    . . .

}

проблема в том, что возвращаемый вами объект AnotherObject() будет уничтожен, как только функция выйдет, и, таким образом, вызывающий объект будет иметь ссылку на фиктивный объект.

Если функция возвращалась по значению, однако:

AnotherObject getAnotherObject()

то копия будет сделана до того, как оригинал будет уничтожен, и все будет в порядке.

Ответ 2

return AnotherObject(); создает объект, который уничтожается до выхода функции - временные файлы уничтожаются в конце выражения, содержащего их [*], а выражение AnotherObject() создает временную.

Так как функция возвращает по ссылке, это означает, что вызывающий объект даже получает возможность увидеть эту ссылку, она больше не относится к допустимому объекту.

Было бы хорошо, если бы функция возвращалась по значению, поскольку временная копия будет скопирована [**].

[*] С несколькими ситуациями, которые этого не делают, но они вам не помогут.

[**] На самом деле существует оптимизация, называемая "копирование конструктора", что означает, что временная необходимость не создается, не копируется и не уничтожается. Вместо этого при определенных условиях компилятору разрешено просто создавать цель копии так же, как она создавала бы временную, и не беспокоить ее вообще.

Ответ 3

Вы создаете временное значение в стеке AnotherObject() и возвращаете его прямо перед тем, как он будет уничтожен. Ваш вызывающий объект получит мусор, и поэтому он запрещен.

Может быть, вы хотите выделить его в куче и вместо этого вернуть указатель?

return new AnotherObject();

В качестве альтернативы объявите свою функцию, чтобы вернуть "копию" к вашему объекту, вместо ссылки, как будто я предполагаю, что вы сейчас возвращаетесь:

AnotherObject f()
{
  return AnotherObject();  // return value optimization will kick in anyway!
}

Ответ 4

Функция должна быть объявлена ​​для возврата ссылки, и ссылка должна ссылаться на объект, который будет продолжать существовать после выхода функции. Ваш временный "AnotherObject()" разрушается сразу после возврата, так что, очевидно, это не сработает. Если вы не можете изменить подпись метода, вам может потребоваться исключить исключение вместо возврата значения ошибки.

Ответ 5

Вы должны изменить возвращаемый тип своей функции из "AnotherObject &" на "AnotherObject" и вернуть этот объект по значению. В противном случае он будет похож на Blindy, описанный

Ответ 6

Вызов конструктора AnotherObject создает новый экземпляр в стеке, который немедленно уничтожается при возврате метода.

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

Если вы хотите это сделать, то вы должны добавить новый объект в структуру данных, а затем вернуть итератор, указывающий на новый объект в структуре данных.

Что-то вроде этого:

if (it == this->end()) {
    it = this->insert(pair<ExString, AnotherObject>( string, AnotherObject() ));
    return  it->second; 
}    

Ответ 7

Вы не должны возвращать ссылку на временную, которая была уничтожена в конце строки, а также ссылка на локальную, которая была уничтожена в конце функции.

Если вы хотите сохранить текущую подпись, вам придется добавить статический константный экземпляр, который вы можете вернуть по умолчанию.

#include <iostream>

template <class T>
class X
{
    T value;
    static const T default_instance;
public:
    X(const T& t): value(t) {}
    const T& get(bool b) const
    {
        return b ? value : default_instance;
    }
};

template <class T>
const T X<T>::default_instance = T();

int main()
{
    X<int> x(10);
    std::cout << x.get(true) << ' ' << x.get(false) << '\n';
}

Вы также можете вернуть по значению или вернуть указатель, в этом случае вы можете вернуть NULL.

Ответ 8

Я лично считаю, что это немного взломать, но пока вы действительно придерживаетесь const'ness возвращаемой ссылки, вы должны иметь возможность вернуть статически сконструированный экземпляр AnotherObject, чей только "raison d'etre" "должно быть" не найденным "возвращаемым значением вашей функции. Например, сделайте его частным членом static const вашего класса Object, и вы должны быть в порядке, если созданный по умолчанию экземпляр AnotherObject не является допустимым значением, которое должно содержаться в экземпляре Object.