【问题标题】:C++ Returning reference to temporary [duplicate]C ++返回对临时的引用[重复]
【发布时间】:2011-04-15 05:32:27
【问题描述】:

可能重复:
warning: returning reference to temporary

我在下面的第二行收到错误“返回对临时的引用”。

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。

我是 C++ 新手,所以我猜测它只是一个语法错误。有什么帮助吗?

【问题讨论】:

  • 代码所在的函数签名是什么?或者该代码的上下文是什么?
  • 我填写了一些细节

标签: c++ reference return-value


【解决方案1】:

如果你的函数看起来像这样:

AnotherObject& getAnotherObject()
{

    . . .

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

    . . .

}

问题在于,一旦函数退出,您返回的 AnotherObject() 将被销毁,因此您的函数的调用者将引用一个虚假对象。

如果你的函数是按值返回的:

AnotherObject getAnotherObject()

然后在原件被销毁之前制作一个副本,你会没事的。

【讨论】:

  • 很好的答案。补充一点,如果您使用new,则应注意此类功能中的泄漏。您应该将它们包裹在 auto_ptrshared_ptr 中,以防止自己不小心泄漏。
【解决方案2】:

return AnotherObject(); 创建一个对象,该对象在函数退出之前被销毁 - 临时对象在包含它们的表达式末尾被销毁[*],而表达式 AnotherObject() 创建一个临时对象。

由于函数通过引用返回,这意味着调用者甚至有机会看到该引用,它不再引用有效的对象。

如果函数按值返回就可以了,因为临时值会被复制[**]。

[*] 有几种情况没有,但在这里对您没有帮助。

[**] 实际上有一个称为“复制构造省略”的优化,这意味着不需要创建、复制和销毁临时。相反,在某些情况下,允许编译器只创建副本的目标,就像它创建临时对象一样,而根本不打扰临时对象。

【讨论】:

    【解决方案3】:

    您正在堆栈AnotherObject() 上创建一个临时值,并在它被销毁之前将其返回。你的函数的调用者会得到垃圾,所以它是被禁止的。

    也许您想在堆上分配它并返回一个指向它的指针?

    return new AnotherObject();
    

    或者,声明您的函数以将“副本”返回到您的对象,而不是像我假设您现在正在返回的引用:

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

    【讨论】:

    • 或者你想按值返回。通常是这样(但显然取决于AnotherObject 的语义)。
    • 哈哈,好久没接触C++了,不过还是猜到了参考部分!
    • return new AnotherObject() 不起作用。我收到一个错误:从“AnotherObject*”类型的表达式中对“const AnotherObject&”类型的初始化引用无效
    • 如果你想返回一个指针,那么返回类型就变成AnotherObject *,就像错误信息说的那样。
    【解决方案4】:

    函数必须声明返回一个引用,并且引用必须引用一个在函数退出后将继续存在的对象。您的临时“AnotherObject()”在返回后立即被破坏,因此显然不起作用。如果无法更改方法签名,则可能需要抛出异常而不是返回错误值。

    【讨论】:

      【解决方案5】:

      您应该将函数的返回类型从“AnotherObject&”更改为“AnotherObject”并按值返回该对象。否则它会像 Blindy 描述的那样发展

      【讨论】:

        【解决方案6】:

        不应返回对在行尾销毁的临时对象的引用,也不应返回对在函数末尾销毁的局部对象的引用。

        如果您想保留当前签名,则必须添加一个静态常量实例,您可以将其作为默认值返回。

        #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。

        【讨论】:

          【解决方案7】:

          调用 AnotherObject 的构造函数在堆栈上创建一个新实例,当方法返回时立即销毁。

          如果查找失败,创建并返回新对象很可能不是一个好主意。调用代码将无法判断返回的对象是否是数据结构中存在的先前存在的对象。

          如果您确实想这样做,那么您应该将新对象添加到数据结构中,然后返回一个指向数据结构中的新对象的迭代器。

          类似这样的:

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

          【讨论】:

          • 你能举个例子吗?
          • @dcinadr 将示例添加到代码中。
          【解决方案8】:

          我个人认为这有点 hack,但只要你真的坚持返回引用的 const'ness,你应该能够返回一个静态构造的 AnotherObject 实例,其唯一的“存在理由” " 将成为您的函数的“未找到”返回值。例如,将其设为 Object 类的静态 const 私有成员,只要默认构造的 AnotherObject 实例不是包含在 Object 实例中的有效值,就可以了。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-14
            • 2012-07-18
            • 1970-01-01
            相关资源
            最近更新 更多