有没有一种正确的方法通过C ++引用返回一个新的对象实例?

时间:2009-06-15 13:45:41

标签: c++ object reference return variable-assignment

所以我写了一些代码,我有类似的东西:

class Box
{
    private:
    float x, y, w, h;

    public:
    //...
    Rectangle & GetRect( void ) const
    {
        return Rectangle( x, y, w, h );
    }
};

稍后在一些代码中:

Rectangle rect = theBox.GetRect();

哪个在我的调试版本中有效,但在发行版中有“问题”通过引用返回Rectangle - 我基本上得到了一个未初始化的矩形。 Rectangle类有一个=运算符和一个复制构造函数。在没有弄清楚为什么会破坏的情况下,我实际上更感兴趣的是通过引用返回(新)对象的正确方法,以便分配复制到变量。我只是傻吗?不应该这样做吗?我知道我可以返回一个指针,然后取消引用,但我不愿意。我的某些部分感觉像按值返回会导致对象的冗余复制 - 编译器是否会解决并优化它?

这似乎是一个微不足道的问题。经过多年的C ++编码后,我感到尴尬,我不知道这一点,所以希望有人可以为我清除这一点。 :)

9 个答案:

答案 0 :(得分:24)

您无法返回对堆栈上临时对象的引用。您有三种选择:

  1. 按值返回
  2. 通过引用返回引用,指向您使用new运算符在堆上创建的内容。
  3. 通过引用将您通过引用收到的内容作为参数返回。 [编辑:感谢@ harshath.jr指出这一点]
  4. 请注意,当您按照下面的代码中的值返回时,编译器应优化分配以避免复制 - 即,它将通过优化create + assign + copy到create中来创建单个Rectangle(rect)。这仅在从函数返回时创建新对象时有效。

    Rectangle GetRect( void ) const
    {
        return Rectangle( x, y, w, h );
    }
    
    Rectangle rect = theBox.GetRect();
    

答案 1 :(得分:15)

不,你不能这样做。基本上,您在此示例中尝试执行的操作是返回对堆栈上的临时变量的引用。返回引用时,它指向的变量将被销毁,因此引用无效。

答案 2 :(得分:7)

按值返回对象(参见下面的示例)实际上可能比您想象的要便宜。编译器通常会优化额外的副本。这称为return value optimization

    Rectangle GetRect( void ) const
    {
            return Rectangle( x, y, w, h );
    }

答案 3 :(得分:3)

  

是否有正确的方式来返回新的   C ++中引用的对象实例?

不,不是参考。有两种方法可以创建新对象:

在堆栈上:

Rectangle makeRect()
{
  return Rectangle(x, y, w, h);
}
Rectangle r = makeRect(); // return by value

在堆上:

Rectangle * makeRect()
{
  return new Rectangle(x, y, w, y);
}
Rectangle * r = makeRect(); // returned a pointer, don't forget to delete it later

为什么不是这样的?

class Box
{
  private:
    Rectangle mRectangle;

  public:
    Box(float x, float y, float w, float h) :
      mRectangle(x, y, w, h) // Forgive me for making assumptions
                             // about the inner workings of your
                             // code here.
    {
    }

    const Rectangle & GetRect() const
    {
      return mRectangle;
    }
};

Rectangle rect = theBox.GetRect();

“任务”现在应该有效。 (从技术上讲,这不是赋值运算符,而是要调用的复制构造函数。)

希望提供帮助

答案 4 :(得分:2)

  • 要么返回对Box课程内部成员的引用(请Rectangle成员。建议返回const引用。)
  • 或只返回Rectangle。请注意,使用惯用语return SomeClass(a,b,c);可能会在合适的编译器上触发return value optimization (RVO)

检查您的std::complex实施细节。

答案 5 :(得分:2)

你可能会对临时生命的概念感到困惑。考虑:

void f1( const A & a ) {
}

A f2() {
   return A;
}

f1( f2() );

这是好的代码,标准说f2创建的无名临时文件必须挂起足够长的时间才能在f1中使用。

但是,你的情况有所不同。函数返回的东西是引用,因此无名临时也是引用。该引用必须挂起足够长的时间才能有用,但它所引用的内容不需要。

答案 6 :(得分:2)

这是不可能的。引用是指针的另一种形式,实际上你返回一个已被销毁的对象的地址(析构函数被调用),甚至可能在调用者获得控制权时被覆盖。

你可以

  • 调用new并返回一个指针(也许你应该想到一个智能指针)到堆分配的对象或
  • 按值返回或
  • 通过引用将对象传递给函数,以便填充它。

答案 7 :(得分:0)

如果矩形按位看起来像Box,即由四个浮点数组成(但有不同的成员函数),你可以使用 reinterpret_cast ,虽然我根本不推荐它:

    const Rectangle & GetRect( void ) const
    {
            assert(sizeof(Rectangle) == sizeof(Box));
            return reinterpret_cast <Rectangle> (*this);
    }

答案 8 :(得分:0)

我们可以使用auto_ptr,如果我们想使用新的和安全的内存泄漏

class Box  { 

  private:    float x, y, w, h;   

  public:    

  //...    

  std::auto_ptr<Rectangle> GetRect( void ) const   
  {        
      return std::auto_ptr<Rectangle> ( new Rectangle( x, y, w, h ));   
  }

};