web-dev-qa-db-ja.com

メンバー変数の参照を返すのは悪い習慣ですか?

以下は、パブリックメンバーとして1番目/ 2番目を持つよりも良いと言われています。これはほぼ同じくらい悪いと思います。クラス外のプライベート変数にアクセスする方法を提供している場合、何がポイントですか?関数はすべきではありません

T First(); void(or T) First(const T&)

サンプル:

// Example 17-3(b): Proper encapsulation, initially with inline accessors. Later
// in life, these might grow into nontrivial functions if needed; if not, then not.
//
template<class T, class U>
class Couple {
  Couple()           : deleted_(false) { }
  T& First()         { return first_; }
  U& Second()        { return second_; }
  void MarkDeleted() { deleted_ = true; }
  bool IsDeleted()   { return deleted_; }

private:
 T first_;
 U second_;
 bool deleted_;
};
46
user34537

クラスの内部への参照(またはポインター)を返すことが悪い理由はいくつかあります。 (私が考えている)最も重要なものから始めます:

  1. カプセル化違反:実装の詳細を漏らしたため、クラスの内部を希望どおりに変更できなくなりました。保存しないことにした場合first_例えば、しかしその場でそれを計算するために、どのようにそれへの参照を返しますか?あなたはできないので、あなたは立ち往生しています。

  2. Invariantは持続可能ではありません(非const参照の場合):誰でも自由に参照される属性にアクセスして変更できるため、その変更を「監視」できません。これは、この属性が一部である不変式を維持できないことを意味します。基本的に、あなたのクラスはブロブに変わりつつあります。

  3. Lifetimeの問題が発生します。属性に属する元のオブジェクトが存在しなくなった後、属性への参照またはポインタを保持するのは簡単です。もちろん、これは未定義の動作です。たとえば、ほとんどのコンパイラは、スタック上のオブジェクトへの参照を保持することを警告しようとしますが、関数またはメソッドによって返される参照に対してこのような警告を生成することができたコンパイラはありません。

そのため、通常、属性への参照またはポインターを提供しない方が良いです。 constのものすらありません!

小さな値の場合、一般的にはコピー(inoutの両方)でそれらを渡すだけで十分です。特に現在(移動中)にセマンティクスを使用しています。

大きな値の場合、状況によって実際に異なります。プロキシがトラブルを緩和する場合があります。

最後に、一部のクラスでは、パブリックメンバーを持つことはそれほど悪くないことに注意してください。 pairのメンバーをカプセル化するポイントは何ですか?属性のコレクション(不変ではない)にすぎないクラスを作成していることに気付いた場合は、代わりにすべてOOを取得し、それぞれのゲッター/セッターのペアを作成する代わりに、代わりに公開することを検討してください。

53
Matthieu M.

templateTおよびUが大きな構造の場合、-値による戻りはコストがかかります。ただし、参照によって返すことは、private変数へのアクセスを許可することと同じです。両方の問題を解決するには、それらをconstリファレンスにします。

_const T& First()  const  { return first_; }
const U& Second() const  { return second_; }
_

P.S。また、setterメソッドがない場合、コンストラクター内で変数を初期化しないでおくのは悪い習慣です。元のコードでは、First()Second()は、両方とも読み取り/書き込み用の_first__と_second__のラッパーのようです。

25
iammilind

答えは、何をしようとしているかによって異なります。参照を返すことは、データ構造の変更を容易にする便利な方法です。良い例はstlマップです。要素への参照を返します。

std::map<int,std::string> a;
a[1] = 1;

あなたがやることを止めるものは何もない

auto & aref = a[1];

それは必ずしも悪い習慣ですか?そうは思いません。あなたがそれなしでできるなら、私はそう言うでしょう。それが生活をより便利で効率的にするなら、それを使用し、あなたがしていることに注意してください。

7
Ramesh Kadambi