web-dev-qa-db-ja.com

C ++ゲッターが返すもの

C++のgetterメソッドのベストプラクティスは、自明ではない型を返しますが、型クラスまたは構造体のメンバーを返すことです。

  1. 次のような値で戻る:MyType MyClass::getMyType() { return mMyType; }
  2. Const参照で戻る:const MyType& MyClass::getMyType() { return mMyType; }
  3. アドレスで返す:MyType* MyClass::getMyType() { return &mMyType; }

どこ

_class MyType { /* ... */ };

class MyClass
{
  private:
     MyType mMyType;
}
_

このメソッドの以下の使用法について特に心配しています。これがオブジェクトのコピーにどのように影響するか、function()がさらに使用するために保存したい場合に参照がぶら下がったり、ポインターが消えてしまう危険性について詳しく説明してください。

_MyType* savedPointer;

SomeType function(MyType* pointer) { savedPointer = pointer; };
_

a。 1.および2.に有効.

_{
  MyType t = myClass.getMyType();
  function(&t);
}

// is savedPointer still valid here?
_

b。 1.および2.に有効.

_{
  const MyType& t = myClass.getMyType();
  function(&t);
}

// is savedPointer still valid here?
_

c。 1.および2.に有効.

_{
  MyType& t = myClass.getMyType();
  function(&t);
}

// is savedPointer still valid here?
_

d。 3に対して有効。

_{
  MyType* t = myClass.getMyType();
  function(t);
}

// is savedPointer still valid here?
_

ここで、myClassMyClass型のオブジェクトです。

43
Ferenc Deak

Constバージョンと非constバージョンの両方を提供できます。

_MyType       & MyClass::getMyType()       { return mMyType; }
MyType const & MyClass::getMyType() const { return mMyType; }
_

ポインターバージョンは提供しません。これは、戻り値がnullポインターである可能性があることを意味しているため、このインスタンスでは決して使用できないためです。

ただし、実際のポイントは、基本的には呼び出し元に内部オブジェクトへの直接アクセスを許可しているということです。これがあなたの意図である場合、データメンバーをパブリックにすることもできます。そうでない場合は、オブジェクトを非表示にするために一生懸命働く必要があります。

1つのオプションは、_MyType const &_アクセサーを保持しますが、内部オブジェクト(setMyType(…)または包含のレベルで表現しようとしているセマンティクスに合わせた何かを変更するためのより間接的な手段を提供することです。クラス)。

19
Marcelo Cantos

一般に、参照がメンバーを指定することを明示的に保証したい場合を除き、値による戻りを選択する必要があります(実装の一部を公開しますが、std::vector<>::operator[])。参照を返すことは、計算値を返すことができないことを意味するため、クラスのその後の変更を防ぎます。 (これは、参照を返すとすべての派生クラスに対してこの制限が作成されるため、クラスが基本クラスとして設計されている場合に特に重要です。)

ポインタで返す必要があるのは、ルックアップまたは何かが関係している場合だけです。これは、nullポインタを返す必要がある場合に戻ります。

プロファイラーがパフォーマンスの問題をここで示している場合、constへの参照を返すことは有効な最適化である可能性があり、呼び出しサイトはconst参照も処理できます(戻り値の変更なし、オブジェクトの有効期間の問題なし)。もちろん、実装上の追加の制約と比較検討する必要がありますが、場合によっては正当化されます。

16
James Kanze

常にconst参照を返します。値を変更する必要がある場合は、setter関数を使用して返すだけです。

3

次のような値による戻り:MyType MyClass::getMyType() { return mMyType; }は、オブジェクトのコンテンツをコピーするため、避ける必要があります。私はあなたが得ることができる利益を見ませんが、パフォーマンスの欠点を見ます。

Const参照で戻る:const MyType& MyClass::getMyType() { return mMyType; }はより一般的にこの方法で使用されます:

_const MyType& MyClass::getMyType() const { return mMyType; }
MyType& MyClass::getMyType() { return mMyType; }
_

常にconstバージョンを提供します。非constバージョンは、誰かがデータを変更できることを意味するため、オプションです。それを使用することをお勧めします。

アドレスで返す:MyType* MyClass::getMyType() { return &mMyType; }は、データがオプションでそこにある場合にほとんど使用されます。多くの場合、使用する前に確認する必要があります。

さて、あなたのユースケース、私はポインタをスコープ以上に保存しないことを強く勧めます。所有権の問題につながることがよくあります。そうする必要があるので、 shared_ptr を見てください。

例として、2つのケースがあります。

a。 savedPointerは、閉じ括弧の後では無効になります。

b、c、およびd。 savedPointerは右中括弧の後に有効ですが、myClassを超えないように注意してください。

1
Johan

a)_MyType t =_は、1と2の両方のオブジェクトのコピーを作成します。tがスコープ外になると、保存されたポインターは無効になります。

b)保存されたポインタは、参照を返すケースでは有効ですが、オブジェクトを返すケースでは無効です。参照の場合、ポインターの有効期間はmyClassと同じです。もちろん、const refの&tはt *ではなくconst t *であるため、function(MyType*)への呼び出しでキャストに失敗します。

c)bと同じですが、_const MyType&_を_MyType&_にキャストできないため、コードは2に対して無効です。通常、これは悪い習慣であり、const形式はより受け入れられます。

d)savedPointerの有効期間はmyClassと同じです。

私は通常、戻り値で何ができると期待するかに応じて、参照またはconst参照を返すことに傾いています。参照(非const)を返す場合、次のようなことができます:myClass.getMyType() = ...、const参照を返す場合、オブジェクトは読み取り専用です。

0
Charlie