所以我正在编写一些代码,我有这样的代码:

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

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

然后在一些代码中:

Rectangle rect = theBox.GetRect();

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

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

有帮助吗?

解决方案

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

  1. 按值返回
  2. 通过指针通过引用返回到您使用 new 运算符在堆上创建的内容。
  3. 通过引用返回您通过引用收到的作为参数的内容。[编辑:感谢@harshath.jr 指出了这一点]

请注意,当您按值返回(如下面的代码所示)时,编译器应优化赋值以避免复制 - 即它只会通过将 create+assign+copy 优化为 create 来创建单个矩形(rect)。仅当您从函数返回时创建新对象时,这才有效。

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

Rectangle rect = theBox.GetRect();

其他提示

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

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

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

是否有正确的方法可以通过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();

“作业”现在应该可以工作了。(从技术上讲,这不是赋值运算符,而是调用的复制构造函数。)

希望能有所帮助

您可能对临时生命周期的概念感到困惑。考虑:

void f1( const A & a ) {
}

A f2() {
   return A;
}

f1( f2() );

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

但是,您的情况有些不同。你的函数返回的是一个引用,因此无名临时也是一个引用。该引用必须保留足够长的时间才能有用,但它所引用的内容则不需要。

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

你可以

  • 调用 new 并返回一个指向堆分配对象的指针(也许您应该想到智能指针)或
  • 按值返回或
  • 通过引用将对象传递到函数中,以便它填充它。
  • 要么返回对你的内部结构的引用 Box 类(有一个 Rectangle 成员。返回一个 const 建议参考)。
  • 或者只是返回一个 Rectangle. 。请注意,使用习语 return SomeClass(a,b,c); 可能会触发 返回值优化(RVO) 在体面的编译器上。

检查你的 std::complex 实施详情。

如果矩形按位看起来像盒子,即由四个浮点数组成(但有不同的成员函数),您可以使用 重新解释_cast, ,尽管我根本不会推荐它:

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

如果我们想使用 new 并且安全地避免内存泄漏,我们可以使用 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 ));   
  }

};
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top