C++ で参照によって新しいオブジェクト インスタンスを返す正しい方法はありますか?
-
13-09-2019 - |
質問
それで、いくつかのコードを書いていたところ、次のようなものができました。
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++ コーディングをしてきたのにこれが分からないのが恥ずかしいくらいなので、誰かがこれを解決してくれることを願っています。:)
解決
スタック上の一時オブジェクトへの参照を返すことはできません。次の 3 つのオプションがあります。
- 値で返す
- new 演算子を使用してヒープ上に作成したものへのポインタを介して、参照によって返されます。
- 引数として参照によって受け取ったものを参照によって返します。[編集:これを指摘してくれた @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 ++での参照によってインスタンスオブジェクト
いいえ、参照することによって。新しいオブジェクトを作成するには、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();
「割り当てが」今動作するはずです。 (技術的に、これは代入演算子ではなく、コピーコンストラクタが呼び出される。)
を支援することを望ん
あなたは、一時の寿命の概念によって混乱することができます。考えてみます:
void f1( const A & a ) {
}
A f2() {
return A;
}
f1( f2() );
これはOKコードで、標準では、F2が作成する無名の一時的で十分な長F1で使用可能であることをラウンドハングしなければならないことを述べています。
しかし、あなたの場合は多少異なります。あなたの関数が戻る事はリファレンスであるため、無名の一時的なも参照です。その参照は有用であると十分な長円形のハングアップしなければならないが、それはいい事をする必要はありませんします。
これは不可能です。参照はポインタの別の形式であり、実際には、呼び出し元が制御を受け取るまでに破棄され ( と呼ばれるデストラクタ)、さらには上書きされるオブジェクトのアドレスを返します。
どちらでもできます
- new を呼び出して、ヒープに割り当てられたオブジェクトへのポインター (スマート ポインターを思い浮かべた方がよいかもしれません) を返すか、
- 値によって返す、または
- オブジェクトを参照によって関数に渡して、そのオブジェクトを埋めます。
- 内部への参照を返すか、
Box
クラス(Rectangle
メンバー。を返すconst
参照することをお勧めします)。 - または単に
Rectangle
. 。イディオムを使用することに注意してくださいreturn SomeClass(a,b,c);
おそらく、 戻り値の最適化 (RVO) まともなコンパイラで。
あなたの std::complex
詳細については実装を参照してください。
ボックスすなわち、4つの浮動小数点数で構成されています(しかし、異なるメンバ関数を得た)のような長方形のビットごとに見える場合、私はまったくお勧めしませんが、あなたは、の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 ));
}
};