2010-12-08 26 views
0

私の質問から、boost :: shared_ptrの使用方法を私のインターフェイスから暴露する必要があるかどうか、そして私のインターフェイスから未処理のポインタや参照を公開する必要があるかどうかについて質問します。混乱についてboost :: shared_ptr

の場合、の従業員があるとします。 従業員は内部ですべての従業員をvector< shared_ptr<Person> >に管理しています。このため、ベスト・プラクティスでは、Personに関係するインタフェースはすべてshared_ptrラップされた人である必要がありますか?私は後で代わりにブースト様々なjohns_very_own_shared_ptr使用するための実装を変更したい場合は

void Employeer::hireByCopy(Person p); 
void Employeer::hireByRef(Person& p); 
void Employeer::hireByRawPtr(Person* p); 
void Employeer::hireBySharedPtr(shared_ptr<Person> p); 

Person Employeer::getPresidentCopy(); 
Person& Employeer::getPresidentRef(); 
Person* Employeer::getPresidentRawPtr(); 
shared_ptr<Person> Employeer::getPresidentSharedPtr(); 

または、例えば:例えば、全部またはこれらOKの一部だけ

をしています、私は古い実装に閉じ込められていますか?

一方、私はインターフェイスから未加工のポインタや参照を公開すると、shared_ptrの下からメモリを削除してしまう人がいるのですか?あるいは、shared_ptrが削除され、私の参照が無効になる危険性がありますか?


これを含む例については、new questionを参照してください。

答えて

3

を、すべて、またはこれらOKの一部だけです:

それは何に依存します達成しようとしている。値によってベクトルPersonを直接格納する代わりに、ベクトルがshared_ptrを保持するのはなぜですか? (そして、あなたはboost::ptr_vectorと考えていますか?)

また、実際に手渡さなければならないものがweak_ptrであると考えてください。

後でブーストバラエティの代わりにjohns_very_own_shared_ptrを使用するように実装を変更したい場合は、古い実装にトラップしますか?

かなり修正できません。 (typedefを使用していないとしても、C++ 0xでは、autoキーワードを自由に使用することで、これを扱いやすくなります。呼び出しコードを変更する必要はないからです)。しかし、それでは、どうしてあなたはになりたいのですか?はそれをしたいのですか?

一方、私がインターフェイスから未処理のポインタまたは参照を公開すると、shared_ptrの下からメモリを削除してしまう人がいますか?

はい、それはあなたの問題ではありません。人々はshared_ptrdeleteから生のポインタを抽出することもできます。しかし、不必要に危険なものにならないようにしたい場合は、生ポインタをここに戻さないでください。参考文献は、と書かれている人は誰もいないので、delete &reference_received_from_api;となっています。 (私はだからこそ、とにかく^^ ;;;;)

+0

従業員の例は、私が当時考え出した最良の例でした。 shared_ptrsを使用している実際のクラスには、実際にその機能が必要です。ありがとう! – JnBrymn

+0

ああ、私はあなたがその機能を必要としていることを完全に信じています。なぜあなたがそうすることができるか、そしてあなたが他の設計上の決定を下すときに考慮すべき異なる理由があります:) –

2

shared_ptrを渡す必要はありませんが、生のポインタを渡すと、オブジェクトが破棄された後にいくつかの生ポインタが存続する危険性があります。

致命的な結果になります。

したがって、一般的にはOK(クライアントコードがアドレスを取る場合はクライアントコードが* shared_ptrのアドレスを取る場合よりもあなたの誤りはそれ以上ありません)。

乾杯& HTH。、

+0

いいアドバイス、ありがとう。それは一般的に参照のアドレスを取るべきではないと受け入れられていますか?それとも私はそのためにコメントをしなければならないのですか? – JnBrymn

2

あなたがshared_ptr Sを使用する場合、私は、ユーザーの生のポインタを与えるべきではありません。ユーザーはそれを削除することができます。何がダブル削除を引き起こしますか。

boost:shared_ptrの使用を非表示にするには、typedefを使用して実際のタイプを非表示にし、代わりにこの新しいタイプを使用できます。

typedef boost::shared_ptr<Person> Person_sptr; 
+0

もっと良いアドバイス。 – JnBrymn

+1

@Alfが指摘しているように、 'shared_ptr'または参照を渡すことは、オブジェクトインスタンスの犯罪的悪用のための万能薬ではありません。 'shared_ptr'とrawポインタを好む理由として、オブジェクトの保護を挙げると誤解を招く。 –

+0

あなたは正しいですが、間違いを防ぐためには十分な保護です。ユーザーは単に 'delete e123.getPresidentSharedPtr();'を実行することはできません。私はユーザーがアプリケーションを中断したいとは思わない、私は彼が間違ってこれを行うことができると思います。 –

3

私はtypedefを紹介し、変更に対して自分自身を守ります。このような何か:

typedef std::shared_ptr<Person> PersonPtr; 

PersonPtr Employeer::getPresident() const; 

私は一緒に前方宣言して(一つだけ)ヘッダにこのような型定義を配置します。これは、私がこれからしたいと思うならば簡単に変更することができます。

1

ここでshared_ptrを渡す唯一の理由は、返されたオブジェクト参照の有効期間が、ベクター内のそのレジデンスの存続期間に直接結び付けられていない場合です。

誰かがEmployeeを停止した後でPersonにアクセスできるようにしたい場合は、shared_ptrが適切です。Personを別のEmployervectorに移動するとします。

+0

Employeerの例は、当時私が思いつくことができる最良の例でした。 shared_ptrsを使用している実際のクラスには、実際にその機能が必要です。しかし、ありがとう。 – JnBrymn

+0

@ジョン - 良い - 重要なのは、コンテナオブジェクトをファイアウォールすることではなく、 'Person'オブジェクトのライフタイムのセマンティクスに関することです。コンテナ内のオブジェクトをファイアウォールする唯一の方法は、コピーを渡すことです。 –

0

私はいくつかのライブラリをリンクする適度なサイズのプロジェクトで作業しています。これらのライブラリの中には、独自のメモリ管理サブシステム(APR、MFC)を持ち、実際に私を悩ませるものがあります。世界の見解が良いか悪いかに関わらず、それはほかの人たちとはまったく異なり、そうでない場合より少しだけコードを必要とします。

はまた、これらのライブラリは、はるかに困難(on Windows it's already hard enough)をjemallocまたはBoehm-Demers-Weiser garbage collectormallocまたはnewをスワップアウトします。

自分のコードで共有ポインタをたくさん使用していますが、他の人に自分のメモリを管理する方法を教えたくないです。代わりに、オブジェクト、可能な限り(図書館利用者が決めるせたときに、どのようにメモリを割り当てるために)、それが不可能なときのいずれかの操作を行い配る:

  1. 手アウト生のポインタ(プラス約束のいずれかをそのポインタができますオブジェクトの割り当てを解除するために呼び出すdelete DまたはDestroy()機能)
  2. あなたはどんなユーザーの使用してメモリ管理のためにフックすることができますので、機能やSTLアロケータのような引数を受け入れ(newstd::allocatorをデフォルトにして自由に感じる)
  3. こと
  4. あなたのライブラリユーザにメモリバッファを割り当ててもらう(like std::vectors
  5. このライブラリの種類を使用して

は厄介である必要はありません。たとえば

// situation (1) from above 
std::shared_ptr<Foo> foo(Library_factory::get_Foo(), Library_factory::deallocate); 

// situation (2) above (declaration on next line is in a header file) 
template<typename allocator=std::allocator<Foo> > Foo* library_function_call(); 
boost::shared_ptr<Foo> foo = library_function_call(); 

// situation (3) above, need to fill a buffer of ten objects 
std::vector<Foo> foo_buffer(10); 
fill_buffer(&foo_buffer[0], foo_buffer.size()); 
関連する問題