在 C++ 中是否有正确的方法通过引用返回新对象实例?

发布于 2024-07-24 04:20:14 字数 637 浏览 3 评论 0 原文

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

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++ 编码,我不知道这一点,我感到几乎尴尬,所以希望有人能为我解决这个问题。 :)

So I was writing some code, and I had something like this:

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

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

Then later in some code:

Rectangle rect = theBox.GetRect();

Which worked in my debug build, but in release there were "issues" returning that Rectangle by reference -- I basically got an uninitialized rectangle. The Rectangle class has an = operator and a copy constructor. Without getting into why this broke, I'm actually more interested in the correct way to return a (new) object by reference for the purpose of assigning copying to a variable. Am I just being silly? Should it not be done? I know I can return a pointer and then dereference on assignment, but I'd rather not. Some part of me feels like returning by value would result in redundant copying of the object -- does the compiler figure that out and optimize it?

It seems like a trivial question. I feel almost embarrassed I don't know this after many years of C++ coding so hopefully someone can clear this up for me. :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

调妓 2024-07-31 04:20:14

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

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

请注意,当您按下面的代码中的值返回时,编译器应该优化分配以避免复制 - 即它只会创建一个矩形(矩形)将创建+分配+复制优化为创建。 仅当您从函数返回时创建新对象时,这才有效。

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

Rectangle rect = theBox.GetRect();

You can't return a reference to a temporary object on the stack. You have three options:

  1. Return it by value
  2. Return by reference via a pointer to something that you created on the heap with the new operator.
  3. Return by reference what you received by reference as an argument. [EDIT: Thanks to @harshath.jr for pointing this out]

Note that when you return by value as in the code below, the compiler should optimize the assignment to avoid the copy - i.e. it will just create a single Rectangle (rect) by optimizing the create+assign+copy into a create. This only works when you create the new object when returning from the function.

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

Rectangle rect = theBox.GetRect();
长不大的小祸害 2024-07-31 04:20:14

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

No you cannot do this. Essentially what you're trying to do in this sample is return a reference to a temporary variable on the stack. By the time the reference is returned, the variable it's pointing to will be destroyed and hence the reference is invalid.

羞稚 2024-07-31 04:20:14

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

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

Returning an object by value (see example below) may actually be less expensive than you think. The compiler often optimizes out the extra copy. This is called the return value optimization.

    Rectangle GetRect( void ) const
    {
            return Rectangle( x, y, w, h );
    }
无尽的现实 2024-07-31 04:20:14

是否有正确的方法返回新的
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();

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

希望有所帮助

Is there a right way to return a new
object instance by reference in C++?

No, not by reference. There are two ways to create a new object:

On the stack:

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

On the heap:

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

Why not something like this?

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();

The 'assignment' should work now. (Technically this is not an assignment operator, but a copy constructor being invoked.)

Hoping to help

乞讨 2024-07-31 04:20:14

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

void f1( const A & a ) {
}

A f2() {
   return A;
}

f1( f2() );

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

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

You may be getting confused by the concept of the lifetime of a temporary. Consider:

void f1( const A & a ) {
}

A f2() {
   return A;
}

f1( f2() );

This is OK code, and the standard says that the nameless temporary that f2 creates must hang round long enough to be useable in f1.

However, your case is somewhat different. The thing your function returns is a reference, and therefore the nameless temporary is also a reference. That reference must hang round long enough to be useful, but the thing it refers to need not.

ゃ人海孤独症 2024-07-31 04:20:14

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

您可以

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

This is not possible. A reference is another form of a pointer and you in fact return an address of an object that will have been destroyed (destructor called ) and possibly even overwritten by the time the caller receives control.

You can either

  • call new and return a pointer (maybe you should think of a smart pointer) to a heap-allocated object or
  • return by value or
  • pass the object by reference into a function so it fills it.
吾性傲以野 2024-07-31 04:20:14
  • 要么返回对 Box 类内部的引用(有一个 Rectangle 成员。建议返回 const 引用)。
  • 或者只返回一个矩形。 请注意,使用习惯用法 return SomeClass(a,b,c); 可能会触发 在不错的编译器上进行返回值优化 (RVO)

检查您的 std::complex 实现以了解详细信息。

  • Either return a reference to the innards of your Box class (have a Rectangle member. Returning a const reference is advised).
  • or just return a Rectangle. Note that using the idiom return SomeClass(a,b,c); will probably trigger a return value optimization (RVO) on decent compiler.

Check your std::complex implementation for details.

悟红尘 2024-07-31 04:20:14

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

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

If the rectangle bitwise looks like the Box i.e consists of four floats (but got different member functions) you could use a reinterpret_cast, although I would not at all recommend it:

    const Rectangle & GetRect( void ) const
    {
            assert(sizeof(Rectangle) == sizeof(Box));
            return reinterpret_cast <Rectangle> (*this);
    }
£冰雨忧蓝° 2024-07-31 04:20:14

如果我们想使用 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 ));   
  }

};

we can use auto_ptr, if we want to use new and safe from Memory Leak

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 ));   
  }

};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文