简体   繁体   English

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

[英]Is there a right way to return a new object instance by reference in 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. 哪个在我的调试版本中有效,但在发行版中有“问题”通过引用返回Rectangle - 我基本上得到了一个未初始化的矩形。 The Rectangle class has an = operator and a copy constructor. Rectangle类有一个=运算符和一个复制构造函数。 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. 经过多年的C ++编码后,我感到尴尬,我不知道这一点,所以希望有人可以为我清除这一点。 :) :)

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. 通过引用返回引用,指向您使用new运算符在堆上创建的内容。
  3. Return by reference what you received by reference as an argument. 通过引用将您通过引用收到的内容作为参数返回。 [EDIT: Thanks to @harshath.jr for pointing this out] [编辑:感谢@ harshath.jr指出这一点]

Note that when you return by value as in the code below, the compiler should optimize the assignment to avoid the copy - ie it will just create a single Rectangle (rect) by optimizing the create+assign+copy into a create. 请注意,当您按照下面的代码中的值返回时,编译器应优化分配以避免复制 - 即,它将通过优化create + assign + copy到create中来创建单个Rectangle(rect)。 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();

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. 返回引用时,它指向的变量将被销毁,因此引用无效。

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

Is there a right way to return a new object instance by reference in C++? 有没有一种正确的方法通过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 希望能帮到你

  • Either return a reference to the innards of your Box class (have a Rectangle member. Returning a const reference is advised). 返回对Box类内部的引用(具有Rectangle成员。建议返回const引用)。
  • or just return a Rectangle . 或者只返回一个Rectangle Note that using the idiom return SomeClass(a,b,c); 注意使用成语return SomeClass(a,b,c); will probably trigger a return value optimization (RVO) on decent compiler. 可能会在合适的编译器上触发返回值优化(RVO)

Check your std::complex implementation for details. 检查std::complex实现以获取详细信息。

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. 这是好的代码,标准说f2创建的无名临时必须挂起足够长的时间才能在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. 该引用必须挂起足够长的时间才能有用,但它引用的内容不需要。

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 调用new并返回一个指针(也许你应该想到一个智能指针)到堆分配的对象或
  • return by value or 按价值或
  • pass the object by reference into a function so it fills it. 通过引用将对象传递给函数,以便填充它。

If the rectangle bitwise looks like the Box ie consists of four floats (but got different member functions) you could use a reinterpret_cast , although I would not at all recommend it: 如果矩形按位看起来像Box,即包含四个浮点数(但有不同的成员函数),你可以使用reinterpret_cast ,虽然我根本不会推荐它:

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

we can use auto_ptr, if we want to use new and safe from Memory Leak 我们可以使用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 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM