スマート ポインター + 「これ」は有害だと考えられますか?
-
23-08-2019 - |
質問
次のようなスマート ポインターを使用する C++ プロジェクトの場合 boost::shared_ptr
, 、「」の使用に関する優れた設計哲学は何ですか?this
"?
次のことを考慮してください。
スマート ポインターに含まれる生のポインターを後で使用するために保存するのは危険です。オブジェクトの削除の制御を放棄し、スマート ポインターが適切なタイミングで削除を実行してくれると信頼しています。
非静的クラスのメンバーは本質的に
this
ポインタ。これは生のポインタであり、変更できません。
もし私が保管することがあれば this
別の変数に保存したり、後で保存したりコールバックにバインドしたりできる別の関数に渡すと、誰かが私のクラスへの共有ポインターを作成することを決定したときに発生するバグを作成しています。
そう考えると、明示的に this
ポインタ? これに関連するバグを防ぐことができる設計パラダイムはありますか?
解決
一般的な答えや慣用句はありませんが、次のようなものがあります。 boost::enable_shared_from_this
。これにより、shared_ptr によって既に管理されているオブジェクトを管理するshared_ptr を取得できます。メンバー関数では、shared_ptr を管理する関数への参照がないため、enable_shared_ptr を使用すると、shared_ptr インスタンスを取得し、this ポインターを渡す必要があるときにそれを渡すことができます。
しかし、これでは合格の問題は解決されません this
この時点ではまだオブジェクトを管理しているshared_ptrが存在しないため、コンストラクター内から実行します。
他のヒント
間違った質問
スマート ポインターを使用する C++ プロジェクトの場合
この問題は実際にはスマート ポインターとは何の関係もありません。それは所有権についてのみです。
スマートポインターは単なるツールです
特に所有権の概念以外は何も変わりません。 プログラム内で明確に定義された所有権を持つ必要性, 、所有権は自発的に譲渡できるが、クライアントが取得することはできないという事実。
スマート ポインター (ロックやその他の RAII オブジェクトも) は、値と、この値に関する関係を同時に表すことを理解する必要があります。あ shared_ptr
はオブジェクトへの参照であり、関係を確立します。この前にオブジェクトを破棄してはなりません shared_ptr
, 、そしてこのとき shared_ptr
が破棄された場合、それがこのオブジェクトのエイリアスを作成する最後のものである場合、オブジェクトは直ちに破棄されなければなりません。(unique_ptr
の特殊なケースとして見ることができます shared_ptr
ここで、定義上エイリアシングはゼロであるため、 unique_ptr
は常にオブジェクトのエイリアスを作成する最後のものです)。
スマート ポインターを使用する必要がある理由
スマート ポインタは変数と関数の宣言だけで多くのことを表現できるため、スマート ポインタを使用することをお勧めします。
スマート ポインターは、明確に定義されたデザインのみを表現でき、所有権を定義する必要性がなくなるわけではありません。対照的に、ガベージ コレクションでは、メモリの割り当て解除の責任者を定義する必要がなくなります。(ただし、他のリソースのクリーンアップの責任者を定義する必要性がなくなるわけではありません。)
純粋に関数型ではないガベージ コレクション言語であっても、所有権を明確にする必要があります。他のコンポーネントがまだ古い値を必要とする場合は、オブジェクトの値を上書きしたくないでしょう。これは特に Java に当てはまり、スレッド プログラムでは可変データ構造の所有権の概念が非常に重要です。
生のポインタはどうなるでしょうか?
raw ポインターの使用は、所有権がないことを意味するものではありません。それは変数宣言によって記述されていないだけです。コメントや設計書などに記述できます。
このため、多くの C++ プログラマーは、適切なスマート ポインターの代わりに生のポインターを使用するのが適切であると考えています。 劣った:表現力が乏しいからです(「良い」と「悪い」という言葉を意図的に避けています)。Linux カーネルは、関係を表現するためにいくつかの C++ オブジェクトを使用するとさらに読みやすくなると思います。
スマート ポインターの有無にかかわらず、特定のデザインを実装できます。スマート ポインターを適切に使用する実装は、多くの C++ プログラマーによって優れていると考えられます。
あなたの本当の質問
C++ プロジェクトにおける「this」の使用に関する優れた設計哲学は何ですか?
それはとても曖昧です。
後で使用するために生のポインタを保存するのは危険です。
後で使用するためにポインターが必要なのはなぜですか?
オブジェクトの削除の制御を放棄し、責任のあるコンポーネントが適切なタイミングでそれを実行すると信頼しています。
実際、一部のコンポーネントが変数の有効期間を担当します。あなたは責任を負うことができません:それは転送されなければなりません。
これを別の変数に保存したり、後で保存したりコールバックにバインドしたりできる別の関数に渡したりすると、誰かが私のクラスを使用することを決定したときにバグが発生することになります。
明らかに、呼び出し元には、関数がポインターを非表示にし、後で呼び出し元の制御なしにそれを使用することが通知されていないため、バグが発生します。
解決策は明らかに次のいずれかです。
- オブジェクトの存続期間を処理する責任を関数に移す
- ポインタが呼び出し元の制御下でのみ保存および使用されるようにする
最初のケースのみ、クラス実装でスマート ポインターが使用される可能性があります。
あなたの問題の原因
あなたの問題は、スマート ポインターを使用して問題を複雑にしようと努めていることだと思います。スマート ポインターは、物事を難しくするのではなく、簡単にするツールです。スマート ポインターが仕様を複雑にする場合は、より単純な観点から仕様を再考してください。
問題が発生する前に、解決策としてスマート ポインターを導入しようとしないでください。
明確に定義された特定の問題を解決するためにのみ、スマート ポインターを導入してください。明確に定義された特定の問題を説明していないため、 具体的な解決策について議論することはできません (スマート ポインターを含むかどうか)。
正しい使い方の一例は、オペレータのような関数でreturn *this;
++()オペレータである<<()。
スマート ポインター クラスを使用している場合、直接公開するのは危険です。this
」。関連するポインタークラスがいくつかあります。 boost::shared_ptr<T>
それは役に立つかもしれません:
boost::enable_shared_from_this<T>
- オブジェクトへの既存の共有ポインタと同じ参照カウント データを使用する、オブジェクト自体への共有ポインタを返す機能を提供します。
boost::weak_ptr<T>
- 共有ポインターと連携して動作しますが、オブジェクトへの参照は保持しません。すべての共有ポインタが消えてオブジェクトが解放された場合、弱いポインタはそのオブジェクトがもう存在しないことを示し、ユーザーを返します。
NULL
無効なメモリへのポインタの代わりに。ウィーク ポインタを使用すると、有効な参照カウント オブジェクトへの共有ポインタを取得できます。
- 共有ポインターと連携して動作しますが、オブジェクトへの参照は保持しません。すべての共有ポインタが消えてオブジェクトが解放された場合、弱いポインタはそのオブジェクトがもう存在しないことを示し、ユーザーを返します。
もちろん、これらはどちらも確実というわけではありませんが、少なくとも、オブジェクトに適切なアクセスと参照カウントを提供しながら、コードの安定性と安全性を高めることができます。
this
を使用する必要がある場合は、、ちょうどそれを明示的に使用しています。 exclusivelly(unique_ptr
)のいずれか、または共有の方法(shared_ptr
)に - スマートポインタは、唯一、自分が所有するオブジェクトのポインタをラップします。
私は個人的には、クラスのメンバ変数にアクセスするときのこののポインタを使用したいです。たとえばます:
void foo::bar ()
{
this->some_var += 7;
}
これは、スタイルだけの無害な問題です。それのような一部の人々は、somepeopleません。
しかし、他のもののためのこののポインタを使用することで問題を引き起こす可能性があります。あなたが本当にそれで派手なことを行う必要がある場合は、あなたが本当にあなたのデザインを再考する必要があります。私はかつて、クラスのコンストラクタで、それはどこかに保存された別のポインタにこのポインタを割り当てられ、いくつかのコードを見ました!それはちょうどクレイジーだ、と私は今までそれをする理由を考えることはできません。全体のコードは方法によって、巨大な混乱だった。
あなたは正確にあなたがポインタでやりたい何をすべきか教えてください。
別のオプションは、侵入スマートポインタを使用して、オブジェクト自体ではなく、ポインタの内部参照カウントの世話をしています。これは、もう少し作業が必要ですが、実際にはより効率的かつ制御が容易である。
この周りを通過するもう1つの理由は、あります。コンストラクタでは、オブジェクトはこれでレジストリの静的メソッドを呼び出します。そのために有用な様々なメカニズムをパブリッシュ/サブスクライブ、またはレジストリは、/クラスがシステム内にあるオブジェクトを何の知識を必要としたくないときます。