11

などのスマート ポインターを使用する C++ プロジェクトでboost::shared_ptr、" " の使用に関する優れた設計哲学は何thisですか?

次のことを考慮してください。

  • スマート ポインターに含まれる生のポインターを後で使用するために保存するのは危険です。オブジェクトの削除の制御をあきらめ、スマート ポインターが適切なタイミングでそれを実行することを信頼します。

  • 非静的クラス メンバーは、本質的にthisポインターを使用します。これは生のポインターであり、変更することはできません。

別の変数に保存thisしたり、後で保存したり、コールバックでバインドしたりする可能性のある別の関数に渡すと、誰かがクラスへの共有ポインターを作成することを決定したときに導入されるバグが作成されます。

thisそれを考えると、ポインタを明示的に使用することが適切なのはいつですか? これに関連するバグを防ぐことができる設計パラダイムはありますか?

4

8 に答える 8

15

間違った質問

スマート ポインターを使用する C++ プロジェクトの場合

この問題は、実際にはスマート ポインターとは何の関係もありません。それは所有権についてのみです。

スマートポインターは単なるツールです

彼らは所有権の概念、特にWRTを何も変えません。プログラムで明確に定義された所有権を持つ必要性、所有権は自発的に譲渡できますが、クライアントが取得することはできないという事実。

スマート ポインター (ロックやその他の RAII オブジェクトも) は、値と、この値を WRT する関係を同時に表すことを理解する必要があります。Ashared_ptrはオブジェクトへの参照であり、関係を確立します。オブジェクトは、 thisshared_ptrの前に破棄されてはなりません。また、 thisshared_ptrが破棄されたときに、これがこのオブジェクトの最後のエイリアスである場合、オブジェクトはすぐに破棄されなければなりません。(は、定義によりエイリアシングがゼロunique_ptrの特殊なケースと見なすことができるため、は常にオブジェクトのエイリアシングの最後のものです。)shared_ptrunique_ptr

スマート ポインターを使用する理由

変数や関数の宣言だけで多くのことを表現するため、スマート ポインターを使用することをお勧めします。

スマート ポインターは、明確に定義された設計のみを表現できます。所有権を定義する必要がなくなるわけではありません。対照的に、ガベージ コレクションでは、メモリの割り当て解除の責任者を定義する必要がなくなります。(ただし、他のリソースのクリーンアップの責任者を定義する必要性を取り除かないでください。)

ガベージ コレクションが純粋に機能しない言語であっても、所有権を明確にする必要があります。他のコンポーネントがまだ古い値を必要としている場合は、オブジェクトの値を上書きしたくありません。これは、スレッド化されたプログラムで可変デー​​タ構造の所有権の概念が非常に重要である Java で特に当てはまります。

生のポインターはどうですか?

生のポインターを使用しても、所有権がないわけではありません。変数宣言で記述されていないだけです。コメント、設計ドキュメントなどに記述できます。

そのため、多くの C++ プログラマーは、適切なスマート ポインターの代わりに生のポインターを使用することは劣っていると考えています。これは、表現力が低いためです (意図的に「良い」と「悪い」という用語を避けています)。Linux カーネルは、関係を表現するためにいくつかの C++ オブジェクトを使用すると、より読みやすくなると思います。

スマート ポインターの有無にかかわらず、特定のデザインを実装できます。スマート ポインターを適切に使用する実装は、多くの C++ プログラマーによって優れていると見なされます。

あなたの本当の質問

C++ プロジェクトで、"this" の使用に関する優れた設計哲学は何ですか?

それはひどく漠然としています。

後で使用するために生のポインターを保存するのは危険です。

後で使用するためにポインターが必要なのはなぜですか?

オブジェクトの削除の制御を放棄し、責任のあるコンポーネントが適切なタイミングでそれを実行することを信頼しています。

実際、一部のコンポーネントは変数の存続期間に関与しています。責任を負うことはできません。譲渡する必要があります。

これを別の変数に保存したり、後で保存したり、コールバックでバインドしたりする可能性のある別の関数に渡すと、誰かが私のクラスを使用することを決定したときに導入されるバグが発生します。

明らかに、関数がポインターを非表示にし、呼び出し元の制御なしで後でそれを使用することが呼び出し元に通知されないため、バグが作成されます。

解決策は明らかに次のいずれかです。

  • オブジェクトの存続期間を処理する責任を関数に移す
  • ポインターが呼び出し元の制御下でのみ保存および使用されるようにする

最初のケースでのみ、クラスの実装でスマート ポインターになる可能性があります。

あなたの問題の原因

あなたの問題は、スマートポインターを使用して問題を複雑にしようとしていることにあると思います。スマート ポインターは、物事を難しくするのではなく、簡単にするためのツールです。スマート ポインターが仕様を複雑にする場合は、より単純な観点から仕様を再考してください。

問題が発生する前に、ソリューションとしてスマート ポインターを導入しようとしないでください。

明確に定義された特定の問題を解決するためにのみ、スマート ポインターを導入します。明確に定義された特定の問題について説明していないため、特定の解決策(スマート ポインターを含むかどうか)について議論することはできません。

于 2011-10-26T03:13:40.407 に答える
13

一般的な答えやイディオムはありませんが、ありますboost::enable_shared_from_this。これにより、すでに shared_ptr によって管理されているオブジェクトを管理する shared_ptr を取得できます。メンバー関数では、shared_ptr を管理するものへの参照がないため、enable_shared_ptr を使用すると、shared_ptr インスタンスを取得して、this ポインターを渡す必要があるときにそれを渡すことができます。

しかし、これはコンストラクター内からの受け渡しの問題を解決しthisません。その時点ではまだ shared_ptr がオブジェクトを管理していないからです。

于 2008-12-19T20:55:25.763 に答える
5

正しい使用例の 1 つはreturn *this;、operator++() や operator<<() などの関数です。

于 2008-12-19T21:22:40.153 に答える
5

スマート ポインター クラスを使用している場合、" " を直接公開するのは危険thisです。これに関連するいくつかのポインター クラスが役立つboost::shared_ptr<T>可能性があります。

  • boost::enable_shared_from_this<T>
    • オブジェクトへの既存の共有ポインターと同じ参照カウント データを使用する、それ自体への共有ポインターをオブジェクトに返す機能を提供します。
  • boost::weak_ptr<T>
    • 共有ポインターと連携して動作しますが、オブジェクトへの参照は保持しません。すべての共有ポインターがなくなり、オブジェクトが解放された場合、弱いポインターはオブジェクトが存在しなくなったことを伝えることができ、NULL無効なメモリへのポインターの代わりにユーザーを返します。ウィーク ポインターを使用して、有効な参照カウント オブジェクトへの共有ポインターを取得できます。

もちろん、どちらも絶対確実というわけではありませんが、オブジェクトに適切なアクセスと参照カウントを提供しながら、少なくともコードの安定性と安全性を高めることができます。

于 2008-12-19T22:20:26.263 に答える
1

もう 1 つのオプションは、侵入型のスマート ポインターを使用し、ポインターではなく、オブジェクト自体の中で参照カウントを処理することです。これにはもう少し作業が必要ですが、実際にはより効率的で制御が簡単です。

于 2009-01-19T09:27:37.257 に答える
1

を使用する必要がある場合はthis、明示的に使用してください。スマート ポインターは、所有するオブジェクトのポインターのみをラップします (排他的 ( unique_ptr) または共有方法 ( shared_ptr))。

于 2008-12-19T20:56:39.503 に答える
1

個人的には、クラスのメンバー変数にアクセスするときにthisポインターを使用するのが好きです。例えば:

void foo::bar ()
{
    this->some_var += 7;
}

それは無害なスタイルの問題です。好きな人もいれば、嫌いな人もいます。

ただし、thisポインターを他のものに使用すると、問題が発生する可能性があります。それを使って派手なことをする必要がある場合は、デザインを本当に再考する必要があります. クラスのコンストラクターで、 this ポインターを別の場所に格納されている別のポインターに割り当てるコードを見たことがあります。それはただの狂気であり、そうする理由が思いつきません。ちなみに、コード全体がめちゃくちゃでした。

ポインターで正確に何をしたいのか教えていただけますか?

于 2008-12-19T21:05:16.977 に答える
0

これを回避するもう 1 つの理由は、すべてのオブジェクトの中央レジストリを維持したい場合です。コンストラクターでは、オブジェクトはこれを使用してレジストリの静的メソッドを呼び出します。これは、さまざまなパブリッシュ/サブスクライブ メカニズムに役立ちます。または、レジストリにシステム内のオブジェクト/クラスの情報を必要としない場合に役立ちます。

于 2008-12-19T22:07:43.013 に答える