Qtのシグナルとスロットに関してdeleteとdeleteLaterはどのように機能しますか?

StackOverflow https://stackoverflow.com/questions/4888189

  •  28-10-2019
  •  | 
  •  

質問

クラスQNetworkReplyのオブジェクトがあります。そのfinished()信号に接続されたスロットが(他のオブジェクトに)あります。信号は同期しています(デフォルトの信号)。スレッドは1つだけです。

ある時点で、両方のオブジェクトを削除したいと思います。それ以上の信号やそれらからの何かはありません。私は彼らがいなくなって欲しい。 まあ、使ってみようと思いました ジェネラコディセタグプレ

しかし、私は本当にできますか? 〜QObjectの仕様は次のように述べています:

保留中のイベントが配信されるのを待っている間にQObjectを削除すると、クラッシュが発生する可能性があります。

「保留中のイベント」とは何ですか? これは、deleteを呼び出しているときに、配信される「保留中のイベント」がすでにいくつかあり、それらがクラッシュを引き起こす可能性があり、実際に存在するかどうかを確認できないことを意味しますか?

それで、私が電話したとしましょう: ジェネラコディセタグプレ

安全のために。

しかし、私は本当に安全ですか? deleteLaterは、制御がそこに到達したときにメインループで処理されるイベントを追加します。すでにそこにあるobj1またはobj2の保留中のイベント(シグナル)があり、deleteLaterが処理される前にメインループで処理されるのを待っていますか? それは非常に残念なことです。 「やや削除された」ステータスをチェックし、すべてのスロットの着信信号を無視するコードを書きたくありません。

役に立ちましたか?

解決

2つの基本的なルールに従う場合、QObjectsの削除は通常安全です(つまり、通常の慣行では、atmに気付いていない病理学的ケースがある可能性があります)。

  • 削除するオブジェクトから(同期、接続タイプ「直接」)シグナルによって直接または間接的に呼び出されるスロットまたはメソッド内のオブジェクトを削除しないでください。 例えば。シグナルOperation :: finished()とスロットManager :: operationFinished()を持つクラスOperationがある場合、そのスロットでシグナルを発行した操作オブジェクトを削除したくありません。 finish()シグナルを発行するメソッドは、発行後も「this」にアクセスし続け(たとえば、メンバーにアクセス)、無効な「this」ポインターを操作する場合があります。

  • 同様に、オブジェクトのイベントハンドラーから同期的に呼び出されるコード内のオブジェクトを削除しないでください。例えば。 SomeWidget :: fooEvent()またはそこから呼び出すメソッド/スロットでSomeWidgetを削除しないでください。イベントシステムは、すでに削除されたオブジェクト->クラッシュで引き続き動作します。

    バックトレースは通常奇妙に見えるため(PODメンバー変数へのアクセス中のクラッシュのように)、特に信号によって最初に開始された数ステップ下で削除が発生する可能性がある複雑な信号/スロットチェーンがある場合は、どちらも追跡が難しい場合がありますまたは削除されたオブジェクトからのイベント。

    このようなケースは、deleteLater()の最も一般的なユースケースです。コントロールがイベントループに戻る前に、現在のイベントを完了できることを確認します。イベントループは、オブジェクトを削除します。もう1つ、キューに入れられた接続/ QMetaObject :: invokeMethod(...、Qt :: QueuedConnection)を使用して、アクション全体を延期する方がよい場合がよくあります。

他のヒント

参照されたドキュメントの次の2行は、答えを示しています。

〜QObject から

保留中のイベントが配信されるのを待っている間にQObjectを削除すると、クラッシュが発生する可能性があります。現在実行中のスレッドとは異なるスレッドに存在する場合は、QObjectを直接削除しないでください。代わりにdeleteLater()を使用してください。これにより、保留中のすべてのイベントが配信された後、イベントループでオブジェクトが削除されます。それに。

具体的には、他のスレッドから削除しないように指示しています。スレッド化されたアプリケーションは1つしかないため、QObjectを削除しても安全です。

それ以外の場合、マルチスレッド環境で削除する必要がある場合は、deleteLater()を使用します。これにより、すべてのイベントの処理が完了すると、QObjectが削除されます。

デルタオブジェクトルール <の1つについて読んで、質問に対する回答を見つけることができます。 / a>これは次のように述べています:

シグナルセーフ(SS)。
安全でなければなりません 以下を含むオブジェクトのメソッドを呼び出す スロット内からのデストラクタ そのシグナルの1つによって呼び出されています。

フラグメント:

基本的に、QObjectは存在をサポートします シグナリング中に削除されました。のために あなたがしなければならないそれを利用する オブジェクトがしようとしないことを確認してください 後に自分のメンバーのいずれかにアクセスする 削除されます。ただし、ほとんどのQt オブジェクトはこのように書かれていません、そして それらがである必要はありません どちらか。このため、 常に電話することをお勧めします を削除する必要がある場合はdeleteLater() その信号の1つの間にオブジェクト、 「削除」する可能性が高いため アプリケーションをクラッシュさせるだけです。

残念ながら、それは必ずしも明確ではありません 「削除」を使用する必要がある場合と deleteLater()。つまり、そうではありません コードパスに 信号源。多くの場合、あなたは持っているかもしれません で「削除」を使用するコードのブロック 今日は安全なオブジェクトもありますが 将来のある時点でこれは同じです コードのブロックが呼び出されてしまう 信号源からそして今突然 アプリケーションがクラッシュしています。唯一の この問題の一般的な解決策は deleteLater()を常に使用します。 一見不要に思える場合。

一般的に、私はデルタオブジェクトルールをすべてのQt開発者にとって必須の読み物と見なしています。優れた読み物です。

私が知る限り、これは主に、オブジェクトが異なるスレッドに存在する場合の問題です。または、実際に信号を処理している間かもしれません。

それ以外の場合、QObjectを削除すると、最初にすべての信号とスロットが切断され、保留中のすべてのイベントが削除されます。Disconnect()を呼び出すとよいでしょう。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top