web-dev-qa-db-ja.com

公式のQtの例とチュートリアルでスマートポインターを使用しないのはなぜですか?

Qtライブラリに関する公式の例とチュートリアルがスマートポインターを使用しないのはなぜですか?ウィジェットの作成と破棄については、newdeleteのみが表示されます。

私は理論的根拠を検索しましたが、それを見つけることができませんでした。歴史的な理由または後方互換性のためである場合を除き、自分自身は見当たりません:ウィジェットコンストラクターが失敗した場合にプログラムを終了させ、try/catchを介して処理することを誰もが望んでいませんブロックはjustいだけです(いくつかの場所で使用されている場合でも)。親ウィジェットが子の所有権を取得する可能性があるという事実も、一部のレベルで親にdeleteを使用する必要があるため、部分的にしか説明しません。

67
Martin

QtはQobjectリソースを管理するために親子モデルに依存しているためです。イベント管理からメモリ管理、描画、ファイル処理などに使用される複合+責任の連鎖パターンに従います。

実際、共有\一意のポインターでQObjectを使用しようとすると、オーバーエンジニアリング(99%の確率)になります。

  1. DeleteLaterを呼び出すカスタム削除機能を提供する必要があります
  2. 親を持つqobjectには、親オブジェクトに既に参照があります。したがって、親が存在する限り、オブジェクトはリークされないことがわかります。取り除く必要があるときは、deleteLaterを直接呼び出すことができます。
  3. 親のないQWidgetには、すでに Qapplicationオブジェクトの参照 があります。ポイント2と同じです。

ただし、QtでRAIIを引き続き使用できます。たとえば、 QPointerQObjectの弱参照として動作します。私は使うだろう QPointer<QWidget> のではなく QWidget*

注:2つの単語:Qt + valgrind。

60
UmNyobe

子供へのスマートポインター

スマートポインタークラス_std::unique_ptr_および_std::shared_ptr_は、メモリ管理用です。このようなスマートポインターがあるということは、ownポインターであることを意味します。ただし、QObjectまたはQObject親を持つ派生型を作成する場合、所有権(クリーンアップの責任)は親QObjectに引き継がれます。その場合、標準ライブラリのスマートポインターは、二重削除を引き起こす可能性があるため、不要であるか、さらには危険です。いいね!

孤児への生のポインタ

ただし、親QObjectなしでヒープにQObject(または派生型)が作成されると、状況は大きく異なります。その場合、生のポインタだけでなく、スマートポインタ、できればオブジェクトへの_std::unique_ptr_を保持する必要があります。そうすれば、リソースの安全性を確保できます。後でオブジェクトの所有権を親QObjectに渡す場合、std::unique_ptr<T>::release()を次のように使用できます。

_auto obj = std::make_unique<MyObject>();
// ... do some stuff that might throw ...
QObject parentObject;
obj->setParent( &parentObject );
obj.release();
_

親を親に渡す前に行うことで例外がスローされる場合、オブジェクトを保持するために生のポインタを使用すると、メモリリークが発生します。ただし、上記のコードはこのようなリークを防ぐためのものです。

より一般的な注意事項

生のポインタをすべて一緒に避けることは現代のC++のアドバイスではなく、owning生のポインタを避けることです。別の最新のC++アドバイスを追加する場合があります:他のプログラムエンティティが所有するオブジェクトにはスマートポインターを使用しないでください。

22
Ralph Tandetzky

あなたはすでにあなた自身の質問に答えました:except if it's for historic reasons/backward compatibility。 QTと同じくらい巨大なライブラリは、そのライブラリを使用するすべての人がC++ 11をサポートするコンパイラを持っていると想定することはできません。 newおよびdeleteは、以前の標準に存在することが保証されています。

ただし、スマートポインターの使用をサポートしている場合は、未加工のポインターよりもスマートポインターを使用することをお勧めします。

13

@Jameyが言ったことに加えて:

巧妙に設計すれば、ウィジェットで削除を使用する必要がなくなる可能性があります。メインウィンドウがあり、その自動オブジェクトを作成し、イベントループでそのウィンドウを実行しているとします。これで、このウィジェットのすべてのアイテムを子として追加できます。そして、これらをMainWindowに直接/間接的に子として追加するため、このメインウィンドウを閉じると、すべてが自動的に処理されます。作成したすべての動的オブジェクト/ウィジェットがMainWindowの子/孫であることを確認する必要があります。したがって、明示的な削除の必要はありません。

10
PRIME
  • QObjectには親が定義されており、プログラムのツリーのような構造により、メモリを非常に効果的に管理できます。

  • Qtのダイナミズムは、ニースの理想を打ち破ります。生のポインタを渡します。 dangling pointerを保持することは簡単ですが、それはプログラミングの一般的な問題です。

  • 実際には弱い参照であるQtスマートポインターはQPointer<T>です
    そしてSTLキャンディーの一部を提供します。

  • std::unique_ptrなどと混合することもできますが、プログラムのQt以外の機械にのみ使用してください。

5
g24l