18

だから私はいくつかのコードを書いていました、そして私はこのようなものを持っていました:

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++コーディングの後で、これがわからないので、ほとんど恥ずかしい思いをします。誰かが私のためにこれを片付けてくれることを願っています。:)

4

9 に答える 9

26

スタック上の一時オブジェクトへの参照を返すことはできません。次の 3 つのオプションがあります。

  1. 値で返す
  2. new 演算子を使用してヒープ上に作成したものへのポインターを介して、参照によって戻ります。
  3. 引数として参照によって受け取ったものを参照によって返します。[編集: これを指摘してくれた @harshath.jr に感謝]

以下のコードのように値で返す場合、コンパイラはコピーを避けるために代入を最適化する必要があることに注意してください。これは、関数から戻るときに新しいオブジェクトを作成する場合にのみ機能します。

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

Rectangle rect = theBox.GetRect();
于 2009-06-15T13:53:59.183 に答える
16

いいえ、これはできません。基本的に、このサンプルで実行しようとしているのは、スタック上の一時変数への参照を返すことです。参照が返されるまでに、それが指している変数は破棄されるため、参照は無効になります。

于 2009-06-15T13:47:14.007 に答える
10

値でオブジェクトを返す (以下の例を参照) ことは、実際には思ったよりコストがかからないかもしれません。多くの場合、コンパイラは余分なコピーを最適化します。これを戻り値の最適化と呼びます。

    Rectangle GetRect( void ) const
    {
            return Rectangle( x, y, w, h );
    }
于 2009-06-15T14:07:27.560 に答える
5

C++で参照によって新しいオブジェクトインスタンスを返す正しい方法はありますか?

いいえ、参照ではありません。新しいオブジェクトを作成するには、次の 2 つの方法があります。

スタック上:

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

「割り当て」は今すぐ機能するはずです。(技術的には、これは代入演算子ではなく、呼び出されるコピー コンストラクターです。)

お役に立てれば幸いです

于 2009-06-15T23:10:31.133 に答える
2
  • Boxクラスの内部への参照を返します(Rectangleメンバーがいます。const参照を返すことをお勧めします)。
  • または単にを返しますRectangle。このイディオムを使用すると、適切なコンパイラで戻り値の最適化(RVO)return SomeClass(a,b,c);がトリガーされる可能性があることに注意してください。

std::complex詳細については、実装を確認してください。

于 2009-06-15T14:02:45.357 に答える
2

一時的なものの寿命の概念に混乱しているかもしれません。検討:

void f1( const A & a ) {
}

A f2() {
   return A;
}

f1( f2() );

これはOKコードであり、標準では、f2が作成する名前のない一時的なものは、f1で使用できるように十分な長さでハングアップする必要があるとされています。

ただし、ケースは多少異なります。関数が返すものは参照であるため、名前のない一時的なものも参照です。その参照は、有用であるために十分長くぶら下がっている必要がありますが、それが参照しているものは必要ありません。

于 2009-06-15T14:04:22.763 に答える
2

これは不可能です。参照はポインタの別の形式であり、実際には、破棄され(デストラクタと呼ばれる)、場合によっては呼び出し元が制御を受け取るまでに上書きされるオブジェクトのアドレスを返します。

あなたはどちらかをすることができます

  • newを呼び出し、ヒープに割り当てられたオブジェクトへのポインター(おそらくスマートポインターを考える必要があります)を返すか、
  • 値で返すまたは
  • オブジェクトを参照によって関数に渡して、オブジェクトを埋めます。
于 2009-06-15T14:04:42.997 に答える
0

四角形がビットごとにボックスのように見える場合、つまり 4 つのフロートで構成されている (ただしメンバー関数が異なる) 場合は、reinterpret_castを使用できますが、まったくお勧めしません。

    const Rectangle & GetRect( void ) const
    {
            assert(sizeof(Rectangle) == sizeof(Box));
            return reinterpret_cast <Rectangle> (*this);
    }
于 2009-06-15T14:12:16.893 に答える
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 ));   
  }

};
于 2009-06-15T15:35:18.597 に答える