簡體   English   中英

有沒有一種正確的方法通過C ++引用返回一個新的對象實例?

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

所以我寫了一些代碼,我有這樣的事情:

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 ++編碼后,我感到尷尬,我不知道這一點,所以希望有人可以為我清除這一點。 :)

您不能返回對堆棧上的臨時對象的引用。 你有三個選擇:

  1. 按價值歸還
  2. 通過引用返回引用,指向您使用new運算符在堆上創建的內容。
  3. 通過引用將您通過引用收到的內容作為參數返回。 [編輯:感謝@ harshath.jr指出這一點]

請注意,當您按照下面的代碼中的值返回時,編譯器應優化分配以避免復制 - 即,它將通過優化create + assign + copy到create中來創建單個Rectangle(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();

“任務”現在應該有效。 (從技術上講,這不是一個賦值運算符,而是一個被調用的復制構造函數。)

希望能幫到你

  • 返回對Box類內部的引用(具有Rectangle成員。建議返回const引用)。
  • 或者只返回一個Rectangle 注意使用成語return SomeClass(a,b,c); 可能會在合適的編譯器上觸發返回值優化(RVO)

檢查std::complex實現以獲取詳細信息。

你可能會對臨時生命的概念感到困惑。 考慮:

void f1( const A & a ) {
}

A f2() {
   return A;
}

f1( f2() );

這是好的代碼,標准說f2創建的無名臨時必須掛起足夠長的時間才能在f1中使用。

但是,你的情況有所不同。 函數返回的東西是引用,因此無名臨時也是引用。 該引用必須掛起足夠長的時間才能有用,但它引用的內容不需要。

這是不可能的。 引用是指針的另一種形式,實際上您返回的對象的地址將被銷毀(析構函數被調用),甚至可能在調用者接收控件時被覆蓋。

你也可以

  • 調用new並返回一個指針(也許你應該想到一個智能指針)到堆分配的對象或
  • 按價值或
  • 通過引用將對象傳遞給函數,以便填充它。

如果矩形按位看起來像Box,即包含四個浮點數(但有不同的成員函數),你可以使用reinterpret_cast ,雖然我根本不會推薦它:

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

我們可以使用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