1

グラフィック ライブラリの一部として quadtree クラスを作成していますが、設計上の問題に直面しています。主な目標は、ライブラリのユーザーが独自のノード タイプでクワッドツリーを簡単に拡張できるようにすることです。各ノードには、その 4 つの子ノードの最初のノードへのポインターがあります。プロトタイプ パターンを使用して、親ノード (実際の型はライブラリに認識されません) を分割するときに 4 回「複製」します。ノードクラスは次のとおりです。

class CNode {
  public:
    virtual CNode* clone();

  protected:
    CNode* pChilds;
}

ライブラリのユーザーは、独自のノードを定義し、traverse メソッドを追加できます。

class MyNode : public CNode {
  public:
    virtual CNode* clone() {
      return new MyNode;
    }

    void myTraverse() {
      if(pChilds[0] != nullptr)
        static_cast<MyNode*>(pChilds[0])->traverse();
    }
}

ご覧のとおり、基本クラスから派生クラスへのキャストを行う必要があります。別の方法として、四分木に関連するすべてのクラス テンプレートを作成することもできますが、実際にはそうしたくありません。ユースブーストも使えません。それに加えて、クアッドツリーはパフォーマンスに重要なコンポーネントであり、可能な限り高速に実行する必要があるため、RTTI または動的キャストを使用した類似のソリューションは遅くなります!

タイプセーフを追加しながら static_cast の速度を維持する可能性はありますか? (四分木には単一タイプのノードのみが含まれます)。

4

2 に答える 2

1

あなたが言ったので

四分木には、単一タイプのノードのみが含まれます

次に、その仮定を使用してコードを最適化できます。のように、 の本体で の子はすべてになると想定でき、MyNode::myTraverse()任意thisの子をsMyNodeに安全に渡すことができます。static_castMyNode

ただし、コード内のバグが、1 つの型の要素しか保持できないというデータ構造の不変条件に違反した場合にどうなるか心配するかもしれません。ここで条件付きコンパイルが役に立ちます。シンボルDEBUGがデバッグ ビルドで定義されていると仮定します。

#ifdef DEBUG
#define my_cast dynamic_cast
#else
#define my_cast static_cast
#endif

...
void MyNode::myTraverse() {
  if(pChilds[0] != nullptr)
    my_cast<MyNode*>(pChilds[0])->traverse();
}

これにより、リリース ビルドでは の速度が得られ、速度がそれほど問題にならないデバッグ ビルドでstatic_castは実行時の型チェックが行われます。dynamic_castまた、リリース ビルドで構造の不変条件に違反している場合、デバッグ ビルドでもそれを行っている可能性があり、デバッグ ビルドはおそらくクラッシュします (実際には未定義の動作になりますが、ほとんどのプラットフォームはクラッシュします)。アクセス違反の例外/セグメンテーション違反で null ポインターを逆参照する場合)。

または、dynamic_cast当面はそのままにして、static_castリリースの準備ができたら、および/またはdynamic_cast代わりに使用することを示すテストを完了したらstatic_cast、許容できないパフォーマンス ヒットになることを示すように切り替えることができます。

編集:そして、ライブラリを作成しているので、いくつかの例を使用して、呼び出されたのと同じタイプのオブジェクトを返さなければならないことがユーザーに非常に明確であることを確認してください。clone()これは、他のプログラマーが間違いを犯していないことを確認できない状況の 1 つであり、他のプログラマーがコメントやドキュメントを読むことができることを信頼する必要があります。

于 2013-09-30T11:05:58.533 に答える