13

ユーザーが私のメンバーの1つを参照できるようにしたいクラスがあるとします。どちらが好ましいですか?

class Member;

class ClassWithWeakPtr
{
private:
   boost::shared_ptr<Member> _member;
public:
   boost::weak_ptr<Member> GetMember();
};

また

class Member;

class ClassWithCppReference
{
private:
    Member _member;
public:
    Member& GetMember() {return _member;}
};

どう思いますか?ある人が他の人より優れているのはいつですか?

4

9 に答える 9

14

を返さないのはなぜshared_ptr<>ですか?そうすれば、クライアントは必要な限り返されたものを使用できますが、「サーバー」クラスがなくなっても問題はありません。

weak_ptr<>のセマンティクスが意味を成す状況はあまり多くありません(キャッシュと ???)。通常、クライアントが何かを要求するときは、その所有権をクライアント自身が決定する必要があります (所有権の共有は、完全な所有権と同じくらい優れています)。

use weak_ptr<>クライアントの知識なしに「サーバー」オブジェクトを破棄できる状況 (またはしたい状況shared_ptr<>) がある場合、できる最悪のことは、メンバーへの参照を返すことです。この場合、クライアントは、返された参照に安全にアクセスできるかどうかを判断できません。メンバーのコピー、または返されるメンバーの有効期間を正しく管理できるスマート ポインターを返す必要があります。

一時的なものを生成する式がある場合ClassWithCppReference(これは必ずしも明白ではありません)、呼び出したクライアントGetMember()は次のステートメントで返された参照を使用することさえできないことに注意してください。

于 2008-10-18T18:57:48.257 に答える
4

効率などに関するコメント (主に OP と Colomon から) に応えて何かを取り上げたいと思います。

私は多くの防御的コピーを行うプログラムを書いてきました。これは Java のイディオムです。すべてのオブジェクトがポインターによって渡されるため、多くのエイリアシングが行われているため、クラスに出入りするものをすべてコピーしてエイリアシングを解除し、クラスのクライアントがクラスの不変条件に違反できないようにします。事後にオブジェクトを変更することによって。

私が書いたプログラムは、リストやマップ全体を含む構造全体を防御的にコピーしました。パフォーマンスが影響を受けないようにするために、プログラムを広範囲にプロファイルしました。主なボトルネックは別の場所にありました (それでも、残りの主なボトルネックがネットワークになるように、他の場所を調整しました)。この防御的なコピーは、プログラムのホット スポットのどこにも登場しませんでした。


ETA: 私のメッセージのポイントを明確にする必要があると感じています. 私が言いたいのは、意地悪で何かをコピーしても大丈夫だということではありません。むしろ、コードがどのように実行されるかを大雑把に推測するのではなく、コードのパフォーマンスを常にプロファイリングする必要があります。

時々、構造全体をコピーしても許容できるパフォーマンスが得られ、同時にコードが書きやすくなる場合、私の意見では、わずかに高速であるがはるかに複雑なコードよりも (ほとんどの場合) 良いトレードオフです。

于 2008-10-18T21:07:26.997 に答える
4

内部を公開することは避けてください。それがガイドラインnです。「C++ コーディング標準」の 42 (Herb Sutter および Andrei Alexandrescu)。何らかの理由で必要がある場合は、 constnessがそれを介して伝播しないため、ポインタではなくconst 参照を返す方がよいでしょう。

weak_ptr<> は、その基本的な目的が shared_ptr のサイクルを回避することであっても、実行可能なソリューションのようです。代わりに、shared_ptr<> を返すと、そのような内部の寿命が延びますが、ほとんどの場合、意味がありません。

誰かがその内部への参照を処理している間に消えるインスタンスの問題は、スレッド間の正しい同期/通信に直面する必要があります。

于 2008-10-18T19:14:56.383 に答える
2

唯一の合理的な答えは、メンバーがクラスにどのように関連しているか、およびクラスのユーザーに何をしてもらいたいかによって決まると思います。_memberClass オブジェクトに依存しない意味のある存在があるか? そうでない場合は、 a を返すか ashared_ptrを返すかに関係なく、 for を使用しても意味がないと思います。本質的には、意味を与える Class オブジェクトよりも長生きする可能性のある Member オブジェクトへのアクセス権をユーザーに与えることになります。これはクラッシュを防ぐかもしれませんが、重大な設計エラーを隠すという代償を払います。weak_ptrshared_ptr

awgn が示すように、クラスの内部を公開する際には十分に注意する必要があります。でも確実に居場所はあると思います。たとえば、私のコードには、ファイル ヘッダー オブジェクトとファイル データ オブジェクトで構成されるファイル オブジェクトを表すクラスがあります。ファイル クラスでヘッダー インターフェイスを完全に複製するのはばかげており、DRY に違反します。おそらく、ユーザーにヘッダー オブジェクトのコピーを取得させ、そのコピーに変更を加えてから、外部オブジェクトを全体のファイル クラスにコピーして戻すことができると思います。しかし、これは多くの非効率性をもたらし、ヘッダーのファイル オブジェクト表現をヘッダー オブジェクト表現とは異なるものにする能力しか得られません。それがやりたいことではないことが確かな場合は、ヘッダーへの非定数参照を返すこともできます-それ'

于 2008-10-18T20:52:32.567 に答える
1

弱いポインタを返すことは間違いなくより高価であり、本当の目的には役立ちません-とにかくメインオブジェクトの寿命より長く所有権を保持することはできません。

于 2009-03-22T00:04:39.060 に答える
1

なぜ弱いポインタを返すのですか?あなたはそれをもっと複雑にしていて、必要な利益はないと思います。

于 2009-03-22T00:06:37.497 に答える
0

私の基本的で無知なガイドライン:

誰かがまだメンバーへの参照を持っている間に ClassWithCppReference のインスタンスが消える可能性がある場合、後者は安全ではない可能性があることを認識しています。ただし、デバイスへのメッセージなど、POD タイプの後者のクラスの引数も確認できますが、常にメンバーをコピーする必要はありません。

于 2008-10-18T18:40:19.293 に答える
-1

文脈によっては、どちらでもかまいません。メンバーへの「ライブ」リンクを返す際の主な問題 (最初に公開する必要がある場合) は、公開されたメンバーを使用する人は誰でも、含まれているオブジェクトが存在するよりも長くクライアントがそれを保持する可能性があることです。また、含まれているオブジェクトがスコープ外になったときにクライアントが参照を介してそのメンバーにアクセスすると、「奇妙な」クラッシュ、間違った値、および同様の楽しみに直面することになります。推奨されません。

weak_ptr<> を返すことには、クライアントがアクセスしようとしているオブジェクトがなくなったことをクライアントに伝えることができるという大きな利点がありますが、これは参照ではできません。

私の 2 ペニーの価値は次のようになります。

  • クライアントがメンバーを使用しない場合、作成者として、それを使用してオブジェクトの有効期間を制御する唯一の人であり、参照を返すことは問題ありません。const 参照はさらに優れていますが、既存のコードを使用した現実の世界では常に可能であるとは限りません。
  • 他の誰かがメンバーにアクセスして使用する場合、特にライブラリを作成している場合は、weak_ptr<> を返します。これにより、多くの手間が省け、デバッグが容易になります。
  • 私は shared_ptr<> を返しません。私はこのアプローチを見てきましたが、通常、weak_ptr/weak 参照の概念に不快感を覚える人々に好まれています。私が見ている主な欠点は、別のオブジェクトのメンバーの寿命を、それを含むオブジェクトのスコープを超えて人為的に延長することです。これは 99% のケースで概念的に間違っており、さらに悪いことに、プログラミング エラー (もう存在しないものにアクセスする) を概念的なエラー (もう存在しないはずのものにアクセスする) に変える可能性があります。
于 2008-10-19T14:46:35.867 に答える