13

私は C++ を初めて使用し、特にゲッターを使用して、所有権について頭を悩ませています。コード例を次に示します。

class GameObject {
public:
  Transform *transform();
private:
  Transform _transform;
};

生のポインターは、オブジェクトが存在しなくなったときに誰かが後でアクセスできるため、使用するのは安全ではないと思いますか?

  1. 変換を所有するのは GameObject だけなので、変換メンバーに unique_ptr を使用することを考えました。しかし、ゲッターからそれを返すことはできませんよね? しかし、繰り返しになりますが、上記のようにメンバーとして追加するのではなく、最初に unique_ptr を使用するのはなぜでしょうか?

  2. では、なぜ shared_ptr を使用しないのでしょうか? 私には間違っているように思えます。所有権を共有したくありません。GameObject が所有者であり、他の人がアクセスする可能性があります...

  3. それで、それは何ですか?参照?他の人が変換への参照を安全に保持できるため、shared_ptr が最も賢明な選択だと思いますが、囲んでいるゲームオブジェクトが破壊されて変換が役に立たなくなったら、それは何の役に立つでしょうか? 私はおそらくここで所有権について間違った方法で考えているだけですが、すべての方法が間違っているように思えます。ご協力いただきありがとうございます。

4

5 に答える 5

18

GameObjectを所有するクラス定義を読んでいる人には明らかです(または明らかなはずです)transform。「共有所有権」が暗示または望まれていないことは正しいです。transformaから aを取得できない可能性はないためGameObject、ポインター (生またはその他) のような null の可能性を表現するものは必要ありませconstん。

生のポインターは安全ではないと言いますが、他の直接アクセス方法よりも安全ではありません。所有されている変換オブジェクト (およびそのコピーではない) へのアクセスを提供する方法は、クライアントがそのアドレスを取得して、所有の存続期間を超えてそれを保存する機会を与えますGameObject。ばかげたことをしないのは本当にクライアント次第です。これを完全に防ぐ方法はないため、インターフェイスをシンプルかつ明確にし、誤って誤って使用されないようにする必要があります。

于 2013-06-11T21:19:29.420 に答える
15

Transform重要なのは、オブジェクトがそのオブジェクトによって所有されているという事実をデザインがモデル化することだと思いますGameObject

所有権が共有されることを意図していない場合 (つまり、オブジェクトの存続期間が、それを所有するTransform唯一の存続期間によって厳密に拘束されている場合) 、.GameObjectshared_ptr

私の意見では、あなたの最初の選択は、実際にすでに選択したものであるべきです: type のサブオブジェクトを持つだけTransformです。ただし、生のポインターではなく、それへの参照を返します。

class GameObject {
public:
    Transform& transform();
private:
    Transform _transform;
};

これは、サブオブジェクトへのアクセスを提供しているが、所有権を提供していないという事実を伝える最も明確な方法です。_transform

クライアントは、「いつ、どのようにこのオブジェクトを削除する必要がありますか? また、まったく削除する必要がありますか? 」などの質問に煩わされる必要はありません。これは、インターフェイスが明確であるためです: 所有権も責任もありません。

一方、これを実行できない理由もあります。考えられる理由の 1 つは、 がオブジェクトGameObjectを所有している場合と所有していない場合があることTransformです。この場合は、unique_ptr代わりに a を使用することをお勧めします (そして、null の可能性がある生のポインターを返します)。

a を使用するもう 1 つの理由unique_ptrは、Transformサブオブジェクトの構築を延期する必要があることです。これは、コンストラクターが計算する必要のあるいくつかの値を受け入れ、コンストラクターの初期化リストで提供できないためです。

一般に、そうする正当な理由がない限り、最も単純な解決策を優先し、 type のサブオブジェクトを埋め込むだけTransformで参照を提供します。

于 2013-06-11T21:21:55.810 に答える
5

経験則: 絶対に避けられない場合にのみ、ポインターと所有権を気にします。C++ は (const ref で拡張された) 優れた値のセマンティクスを備えているため、ポインターが必要になる前に、賢いか愚かかを判断することができます。

あなたの例では、 _transform は直接メンバーとして非常に優れています。ゲッターが欲しければ作れます

Transform transform() const {return _transform; }

いくつかの特別なケースでは、

const Transform& transform() const {return _transform; }

生涯記録付き。正当な理由がある場合にのみ実行してください。

まあ、明らかに、ゲッターへの最善のアプローチは、ゲッターをまったく持たないことです。オブジェクト指向は振る舞いに関するものであり、外部から突っついたりクエリしたりし続けるデータダンプとして使用するのではなく、クラスに仕事をさせます。

于 2013-06-11T21:22:44.500 に答える
2

所有権については他の方がすでに回答されていますが、もう一点付け加えたいと思います。

メンバーへの非constポインターまたは参照を渡すことprivateは、通常、非常に悪い考えです。これは、基本的にそのプライベートメンバーを作成することと同じpublicです。つまり、非 const 参照または非 const メンバーへのポインターを返すゲッターを作成する場合、コードは基本的に次のようになります。

class GameObject {
public:
  Transform _transform; // and you don't have to write a getter
};

しかし、それは悪い考えです。

本当にゲッターを書く必要がある場合は、Balog Pal が提案したプライベート メンバーへの const 参照を指定します。非 const 参照が必要な場合は、設計を再検討する必要があります。

于 2013-06-11T21:59:03.867 に答える