1

一般的に、私は Google のスタイル ガイドに従います。これは、私が物事を見る方法とうまく一致していると感じています。また、ほぼ例外なく、boost::scoped_ptr を使用して、特定のオブジェクトの所有権を 1 人のマネージャーだけが持つようにしています。次に、裸のポインターを渡します。私のプロジェクトは、オブジェクトを使用するオブジェクトが破棄された後、そのオブジェクトのマネージャーが常に破棄されるように構造化されているという考えです。

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Smart_Pointers

これはすべて素晴らしいことですが、所有者を使用していたオブジェクトが削除される前に、所有者がたまたま削除されてしまうという厄介な小さなメモリストンプバグに噛まれました.

さて、みんなが私がこのパターンのばかだと飛び跳ねる前に、単に shared_ptr を使用しないのはなぜですか? など、未定義の所有者セマンティクスを持ちたくないという点を考慮してください。shared_ptr はこの特定のケースをキャッチできますが、システムのユーザーに間違ったメッセージを送信します。「誰がこれを所有しているのかわかりません。あなたかもしれません!」と書かれています。

私を助けたのは、スコープ付きポインターへの弱いポインターだったでしょう。実際には、スコープ付きポインターが破棄されると null になる弱参照のリストを持つスコープ付きポインター。これにより、単一所有権のセマンティクスが可能になりますが、使用中のオブジェクトに、私が遭遇した問題をキャッチする機会が与えられます。

したがって、scoped_ptr の追加の「weak_refs」ポインターと、weak_ptr の「next_weak_ptr」の追加ポインターを犠牲にして、きちんとした小さな単一所有者、複数ユーザー構造を作成します。

それはおそらく単なるデバッグ機能である可能性もあるため、「リリース」では、システム全体が通常のサイズの scoped_ptr と弱参照用の標準の単一ポインターに戻ります。

だから.....これのすべての後の私の質問は次のとおりです。

  1. stl/boost に既にそのようなポインター/パターンがありませんか、それとも自分でロールする必要がありますか?
  2. 私の単一所有権の目標をまだ満たしている、より良い方法はありますか?

乾杯、シェーン

4

4 に答える 4

6

 2.それでも私の単一所有権の目標を達成するより良い方法はありますか?

を使用してくださいshared_ptr。ただし、クラスメンバーとして使用すると、そのクラスの不変条件の一部になり、パブリックインターフェイスは。を取得する方法のみを公開しますweak_ptr

もちろん、病理学的コードは、必要な限り、それから自分自身shared_ptrを保持することができます。weak_ptrここでマキャヴェッリから身を守ることはお勧めしません。マーフィーからのみ身を守ることをお勧めします(サッターの言葉を使用)。一方、ユースケースが非同期の場合、aをロックするとaweak_ptrが返されるという事実shared_ptrが特徴かもしれません。

于 2011-07-28T07:40:13.220 に答える
3

shared_ptrはこの特定のケースを捕らえたはずですが、システムのユーザーに間違ったメッセージを送信します。「誰がこれを所有しているのかわからない、それはあなたかもしれない!」と書かれています。

shared_ptrは、「誰がこれを所有しているのかわからない」という意味ではありません。それは「私たちはこれを所有している」という意味です。1つのエンティティが排他的な所有権を持っていないからといって、誰もがそれを所有できるという意味ではありません。

shared_ptrの目的は、ポインターを共有するすべての人がポインターを破棄することに同意するまで、ポインターを破棄できないようにすることです。

私が行方不明になっているようなポインタ/パッテンがすでにstl/boostにありますか、それとも自分でロールする必要がありますか?

scoped_ptrを使用するのとまったく同じ方法でshared_ptrを使用できます。共有できるからといっ、共有する必要があるわけではありません。それが最も簡単な作業方法です。APIで確立されたルールではなく、単一所有権を慣例にするだけです。

ただし、単一所有者でありながら弱いポインターを持つポインターが必要な場合は、Boostにはありません。

于 2011-07-28T07:41:48.180 に答える
1

弱いポインタがそれほど役立つかどうかはわかりません。通常、コンポーネントXが別のコンポーネントYを使用する場合、ポインタを無効にするだけでなく、おそらくリストからポインタを削除するか、オブジェクトを必要としないように動作モードを変更するために、XにYの終了を通知する必要があります。 。何年も前、私が最初にC ++を始めたとき、良い一般的な解決策を見つけようとする活動が殺到していました。(当時、この問題は関係管理と呼ばれていました。)私が知る限り、優れた一般的な解決策はすべて見つかりませんでした。少なくとも、私が取り組んだすべてのプロジェクトは、オブザーバーパターンに基づいた手作りのソリューションを使用しています。

ManagedPtrそれがまだ稼働していたとき、私は自分のサイトにを持っていました。それはあなたが説明したように振る舞いました。実際には、それをもたらした特定のケースを除いて、通知が常に必要だったので、私はそれの実際の使用法を見つけることができませんでした。ただし、実装は難しくありません。ManagedObject管理対象オブジェクトはクラスから派生し、ManagedPtrそこから渡されるすべてのポインター(rawポインターではなく)を取得します。ポインタ自体はクラスに登録されており、ManagedObjectクラスのデストラクタManagedObjectがそれらすべてにアクセスし、実際のポインタをnullに設定することでそれらを「切断」します。そしてもちろん、クライアントコードが逆参照する前にテストできるようにManagedPtr する機能があります。isValidこれはうまく機能します(オブジェクトの管理方法に関係なく、ほとんどのエンティティオブジェクトはそれ自体を「所有」し、 delete thisは特定の入力への応答です)、ただし、無効にリークする傾向がありManagedPtr(たとえば、クライアントがポインタをある種のコンテナに保持している場合、複数ある可能性があるため)、クライアントは必要に応じて通知されません。オブジェクトが死んだときに何らかのアクションを実行します。

于 2011-07-28T08:01:00.510 に答える
0

たまたま QT を使用している場合、QPointerは基本的に への弱いポインタQObjectです。指し示す値の「I just got destroy」イベントに自身を接続し、必要に応じて自身を自動的に無効にします。ただし、QT のフープをまだジャンプしていない場合は、これはバグ追跡に相当するものを取得するための非常に多額のライブラリです。

于 2011-07-28T08:15:36.650 に答える