QObject の子の順序 (戦略の質問)
質問
私のプロジェクトの 1 つには、QObject の親/子機能を利用してツリーを構築する QObject 派生オブジェクトのツリーがあります。
私はシグナルとスロットを利用し、Qt のガードされたポインターを使用し、親オブジェクトが削除されたときに子も削除することを期待しているため、これは非常に便利です。
ここまでは順調ですね。残念ながら、私のプロジェクトでは、子の順序を管理/変更する必要があります。QObject は、子の順序を変更する手段を提供しません (例外:QWidget の raise() 関数 - ただし、この場合は役に立ちません)。 そこで今、私は子供の順序を制御する戦略を探しています。 いくつかのアイデアがありましたが、長所と短所がわかりません。
オプション A: カスタムソートインデックスメンバー変数
使う int m_orderIndex
メンバー変数をソートキーとして指定し、 sortedChildren()
このキーでソートされた QObject のリストを返すメソッド。
- 既存のオブジェクト構造への実装が簡単です。
- 問題が発生する場合
QObject::children()
メソッドがオーバーライドされます。項目の順序が変更されるとループ中に問題が発生します。また、デフォルトの実装よりもコストがかかります。 - すべてのソートキーが等しいか、0/デフォルトの場合は、QObject オブジェクトの順序にフォールバックする必要があります。
オプション B: 子の冗長リスト
子の冗長リストを維持します。 QList
, 、作成時と破棄時に子を追加します。
- 追加/削除されたオブジェクトの追跡にコストがかかります。これは基本的に、2 番目の子/親の追跡と多くの信号/スロットにつながります。QObject はこれらすべてをすでに内部で実行しているため、再度実行するのは得策ではない可能性があります。また、子供の順序を変更するなどの単純なことで、多くの肥大化が追加されるように感じます。
- 子の QList は必要に応じて変更できるため、柔軟性が優れています。
- 子が QList に複数回存在することを許可するか、まったく存在しないことを許可します (たとえそれがまだ QObject の子である可能性がある場合でも)
オプション C:...?
特に自分のプロジェクトで既にこの問題を解決した人からのアイデアやフィードバックは、非常に高く評価されます。あけましておめでとう!
解決
私はここ数日間、これらすべてのオプションを検討するのに多くの時間を費やし、他のプログラマーと慎重に話し合いました。私たちは行くことにしました オプションA.
私たちが管理している各オブジェクトは、親オブジェクトの子です。Qt にはこれらのオブジェクトを並べ替える手段が提供されていないため、 int m_orderIndex
プロパティを各オブジェクトに設定します。デフォルトは 0 です。
各オブジェクトにはアクセサ関数があります sortedChildren()
を返す QObjectList
子供たちの。その関数で行うことは次のとおりです。
- 通常のものを使用してください
QObject::chilren()
使用可能なすべての子オブジェクトのリストを取得する関数。 dynamic_cast
すべてのオブジェクトを「基本クラス」に追加します。m_orderIndex
財産。- オブジェクトがキャスト可能な場合は、それを一時オブジェクト リストに追加します。
- 使用
qSort
カスタムでLessThan
qSort が 2 つのオブジェクトの順序を変更する必要があるかどうかを確認する関数。 - 一時オブジェクトのリストを返します。
これを行ったのは次の理由からです。
- 既存のコード (特に Qt 自身のコード) は引き続き使用できます。
children()
副作用を心配する必要はありません。 - 通常のものを使用できます
children()
順序が関係ない場所でもパフォーマンスを損なうことなく機能します。 - 子の順序付きリストが必要な場所では、単に次のように置き換えます。
children()
によるsortedChildren()
そして望ましい効果が得られます。
このアプローチの良い点の 1 つは、すべての並べ替えインデックスが 0 に設定されている場合でも、子の順序が変わらないことです。
私自身の質問に答えてしまい申し訳ありませんが、同じ問題を抱えている人々を啓発することを願っています。;)
他のヒント
次のようなものはどうでしょうか...
- QList listChildren = (QList)children();
- ソートリスト子供
- foreach listChildren setParent( TempParent )
- foreach listChildren setParent( OriginalParent )
嫌なハック:はQObject ::子供()の参照を返します。 -to-のconst。あなたはのconstネスを捨てので、直接内部リストを操作することができます。
このはかかわらず、かなり悪である、とはQObjectが内部保持イテレータを無効化する危険性があります。
私は別のオプションCを持っていますが、オプションAとBを比較していない、あなたはように、いずれの場合には〜4バイト(32ビット・ポインタ、32ビット整数を)話していますあなたはそのリストを並べ替えておくことができます。
追跡子どもの追加の複雑さを避けるために、あなたはカンニングと続けるあなたのリストがソートされ、整頓が、すべての非子どもアウトフィルタというsortedChildren方法とそれを組み合わせることができます。複雑賢明な、このいやしくもはO(nlogm)の周りに終わる(N =子供、M =リスト項目、M> = N、すなわち子供が常に追加されていると仮定)あなたは子供に大きな転換がない限りします。レッツは、このオプションCを呼び出します。
などクイックソートは、あなたの提案オプションAで、あなたにO(N2)を与える(WC)、だけでなく、盗んポインタにあなたを必要とし、それらをトレースし、整数を盗ん、組み合わせた方法が唯一のポインタのリストを必要とする(いやしくも)O(N)である。
私は同じ問題を抱えていたし、オプションB.トラッキングがちょうど方法作成、難しいことではありませんで、私はそれを解決し、「無効にaddChild(タイプ* PTRを);」そしてもう一つはChildItemコマンドレットを削除します。
あなたが独占的各項目のプライベート/パブリックたchildList(QListに)以内に子供を保存し、QObjectのベースをドロップする場合は、あなたは悪の冗長性に悩まされません。その実際には非常に簡単(つまり、余分な親ポインタが必要ですが)自由に自動子供フリーを実装する。