2012-03-02 8 views
12

Qtを使ってプログラミングしているときは、この問題はいつも問題になります。 Qtはオブジェクト所有権ツリー​​を使用しているため、ポインタを渡します。 myBoostSharedPtr.get()を介して暗黙的に所有権を譲渡することができます。 いくつかのQtオブジェクトが破棄され、オブジェクトツリー全体が破棄されるがスマートポインタがまだ生きている場合を考えてみましょう。別のクラスのメンバとして その後スマートポインタが削除されるとどうなりますか? すべての厄介な結果を伴うダブル削除? スマートポインタの実装によってこれが防止されていますか?スマートポインタが保持するオブジェクトが他の場所で削除されるとどうなりますか?

+1

私は実際には、QSharedPointerでこの種の問題に遭遇しました。概念的には、boostの 'shared_ptr'と非常によく似ています。私は自分の所見に関するブログエントリを書いた:http://blog.codef00.com/2011/12/15/not-so-much-fun-with-qsharedpointer/ –

答えて

18

私は、Qtのメモリモデルの弱点を突きつけて、ポインタを受け入れたQObjectがそれを削除している間に、クライアントがそれを割り当てても、未処理のポインタを受け入れることができます。

ご質問に対する回答は、です。未定義の動作です。 shared_ptrは、ポインタがshared_ptr以外のものによって削除されたかどうかを検出するメカニズムを持っていないので、通常はポインタをもう一度解放しようとします(ダングリングポインタでdeleteを呼び出します)。 shared_ptrを使いたい場合は、単独のメモリマネージャとしてshared_ptrを使用する必要があります。これはQt自身のQSharedPointerでも当てはまります。私は通常、Qtのようなものを使用した場合、合理的に例外セーフな私のコードを取得しようとするやった

は(unique_ptrがそれに取って代わると、使用可能なC++ 11を持っている場合ははるかに安全である)廃止auto_ptrを使用することでした。それはreleaseメソッドを提供するので、私が今までauto_ptrを使用するように誘惑された唯一の場所です。

unique_ptr<QListWidget> widget(new QListWidget(...)); 
// do stuff with the widget to set it up for your GUI 
some_layout.addWidget(widget.release()); // <-- release ownership so that 
             // the layout now becomes responsible 
             // for memory management 
// ^^ auto_ptr works above if we don't have C++11 

あなたはそれがすでにQtのことで、メモリ管理された後、あなたのオブジェクトに永続的なポインタを保持する必要がある場合(例:あなたはレイアウトに挿入した後、あなたのウィジェットへのポインタ)だけで、通常のポインタを使用し、 。 Qtがそのオブジェクトのメモリマネージャになって以来、あなたができることはあまり良くありません。

しかし、QObject::destroyed信号でオブジェクトが破棄されたとき(したがってポインタが無効になったとき)を検出できます。

本当に洗練されたものにしたい場合は、QObjectのサブクラスのみを格納する共有ポインタ型を作成できます。 QObjectは破壊された信号を提供するので、この種類のカスタムスマートポインタは、QObjectが破棄信号によって破壊されたときに検出し、オブジェクトを2度目に削除しようとしないようにすることができます。しかし、マルチスレッドコードではこの信号に頼りになるかもしれません。共有ポインタを実装すると、ポインタが構築されているサイトで削除関数をキャプチャして、アトミックな参照カウントを処理することにかなりの負担になる可能性があります

+0

私はあなたが引数リストで解放すべきだとは思わない。 'addWidget'がポインタを引き継ぐ前にスローすると、あなたはリークしました。 – GManNickG

+1

@GmanNickGそれは良い点です。あなたは、呼び出しが成功した後にのみ私たちが解放すべきだと思いますか?私はそれを見て、APIはクライアントによって割り当てられたメモリへの生ポインタを受け取ります。一度渡したら、* addWidget *で例外が発生した場合、ポインタのdeleteを呼び出すのはQTの責任です。 QTがaddWidget内のローカルtry/catchブロックでポインタを削除することによってその条件を処理しようとしているかどうかはドキュメントに記載されていません。 addWidgetでポインタを削除して再スローすると、私のunique_ptrがdeleteを呼び出す可能性があります。 – stinky472

+0

@GManNickG ...ぶら下がりポインタです。 addWidgetの実装方法について私が知っていることに非常に依存します。 – stinky472

1

はい、ほとんどの可能性がありますし、そうでない場合もありません。どのように表示されるのかわかりません。あなたは、ポインタを渡しているものが所有権を取らないということを契約書に頼らざるを得ません(ドキュメントに書かれている場合を除きます)。後者の場合は、あなたの側のスマートポインタにそれをラップしません。

1

親QObjectとスマートポインタの間で共有所有権を持たず、他のスマートポインタを削除することはできませんが、QWeakPointerのみを使用して、QObjectの削除を追跡できます(またはQPointer)。

は更新http://qt-project.org/doc/qt-4.8/qweakpointer.html#tracking-qobject

を参照してください:Qtの5では、QWeakPointerQSharedPointerで管理されていないQObject Sを追跡すること(undeprecatedそのものである)QPointerの賛成で廃止されました。

+0

あなたはしないでください。 'QSharedPointer'を使わずに' QWeakPointer'を使うことは、非常に良い理由のために廃止されました。なぜなら、それは_C++ 11_にないのと同じ理由です。 – abergmeier

+0

@abergmeierコメントを残すだけでなく、あなた自身で答えを更新するのではなく、なぜあなたがダウン投票したのか分かりません。 QObject追跡の目的で 'QWeakPointer'を使うことは、書面の時には推奨された方法でした。 – alexisdm

関連する問題