18

新しい配置に対応する配置削除の欠如についての質問に答えていました。その理由operator deleteは、オブジェクトの動的タイプ(検索に使用されるタイプに対応operator new)に応じて呼び出される方法にあるようです。

配置newは私にとって役に立ちました。カスタム割り当てに関しては、おそらく、さまざまなインスタンスがさまざまなプールを管理する再利用可能なクラスがあります。シングルトンはアンチパターンであり、そのすべてです。

new thing;アロケータを追跡せずに作業を行うことの便利さは理解できますが、型階層のさまざまなブランチに対して何かを行うことはかなり複雑に思えます。

派生クラスがそのベースとは異なるアロケータを使用し、仮想デストラクタに依存して正しいメンバーを見つけるという現実のシナリオはありますoperator deleteか?

これが主観的でないように、私は最ももっともらしい答えを受け入れます。コードの臭いや物事を行うための「最良の」方法をいじくりまわさないようにしましょう。

4

4 に答える 4

8

私は過去にこれを実際に使用しました!これは、不均一なメモリアーキテクチャ(OSのない非常に小さい非常に高速なメモリ領域を持つプラットフォームなど)に役立ちます。

具体的には、たとえば、少量のTCMを備えたARMチップ(密結合メモリ、基本的にはSoCに組み込まれたSRAM、たとえば1サイクルのアクセス時間)を想定します。

次に、製品開発の非常に遅い段階(たとえば、これが人気のあるハンドヘルドゲームシステムのカートリッジであると想像してください)のプロファイラーの結果を使用して、特定のクラスがこのより高速なSRAMに含まれることでメリットが得られるかどうかを判断します。

派生クラスだけにこのTCMを利用する単純なメンバーoperator newは、今では理にかなっているかもしれません。このSRAMを使用してクラス階層全体を使用する余裕はありませんが、インスタンス化数が少ないが頻繁に使用される派生クラスの場合は、次のようになります。シンプルで効果的な最適化。この方法で特定の割り当てをリダイレクトすることにより、いくつかのケースでフレーム時間の2%〜10%以上を取り戻しました。

于 2013-05-04T18:15:04.270 に答える
5

私は実際に派生クラスでnew/deleteオーバーロードを使用したことはなく、それについて考えたこともありませんが、この質問は興味深いものであり、調査を行って試してみることにしました。私はいくつかの適切な参考文献を見つけました:

ARM http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka14267.html

このリファレンスには、実際には、派生クラスのサンプルコードがオーバーロードされ、その基本クラスがオーバーロードされています。

ヴァンダービルト大学 http://www.vuse.vanderbilt.edu/~adamsja/Courses/CS251/Projects/4/memPool.pdf

このリファレンスでは、派生クラスでのnewのオーバーロードに関する資料は明示的に提供されていませんが、newをオーバーロードする理由としていくつかの興味深い理由が記載されています。それらの理由は次のとおりです。

  • デフォルトのアロケータで次善の配置を補うため
  • 関連するオブジェクトを互いに近くにクラスター化するには
  • アプリケーションデータのセキュリティを強化するためにゼロでメモリを上書きするなど、従来とは異なる動作を取得するため

これらの2つの参照に基づいて、派生クラスでnew/deleteをオーバーロードする理由がいくつかある可能性があると判断しました。私の理由は、基本的にVUプレゼンテーションからリストした理由と一致していますが、組み込みまたは特殊なシナリオを暗示するARMリファレンスに基づいて関連しているようにも見えます。

  • 組み込みシステムは、ハードウェアレベルでは非常にカスタムであることがよくありますが、ソフトウェアレベルでは標準化された意味で一般的です。構成設定/ハードウェアストラップによっては、特定の方法または特定の場所にメモリを割り当てる必要があるため、実行時に特定のタイプのオブジェクト(派生クラス)が選択される状況が見られました。
  • 一部のオブジェクトが高レベルの「ワークフロー」で同じように扱われるシナリオを想像できるので、クラスタリングはもっともらしいようですが、処理されると、それらのオブジェクトの異なるタイプは非常に異なる方法で処理されます。プロセス集約型のタスク(つまり、検索、並べ替え、優先順位付けなど)のために、特定のタイプのオブジェクトを互いに近くに配置すると便利な場合があります。
  • 最後のポイントは、格納されている情報のセキュリティ分類に割り当てが依存する特定のケースを見ることができたので興味深いです。

繰り返しになりますが、私はあなたが言及したような理由を見つけたり、実際に何かを実装したことはありませんが、これらは少し調査した私の考えです。

于 2013-05-02T21:31:57.823 に答える
1

派生クラスがそのベースとは異なるアロケータを使用し、仮想デストラクタに依存して正しいメンバーを見つけるという現実のシナリオはありますoperator deleteか?

実際のシナリオをどのように考えるかはわかりませんが、私の頭に浮かぶ明らかな例は、抽象基本クラスに根ざした継承階層であり、その多くは(サイズが)大きく異なる派生クラスです。定期的に作成および破棄されますが、これらの割り当て/割り当て解除には速度が必要です。

特定のサイズのメモリブロブのアロケータは非常に高速である可能性があるため、これらの派生クラスのカスタムアロケータが必要になる場合があります。また、派生クラスごとにサイズが非常に異なるため、異なるアロケータを使用する場合があります。

ただし、これについて具体的な例を示すことはできません。何年にもわたって、割り当て/割り当て解除を回避する方が、高速化するよりもはるかに効果的であることがわかったため、ほぼ20年間、クラス固有のnew/をオーバーロードすることはめったにありませんdelete。(もちろん、洗練された最適化について話しているときはいつものように、「ゲーム」が登場するので、膨大な量の非常に異なるエンティティを作成および破棄する必要があるゲームを想像することができます。)

于 2013-05-02T18:07:23.697 に答える
0

メンバーoperator new/deleteは、たとえば、ベースが拡張されることを意図していない場合に、ベースクラスから望ましくないカスタム割り当てを削除するのに役立つ場合があります。ただし、ベースには仮想デストラクタが必要であるか、ベースオブジェクトがのサブジェクトであってはなりませんdelete

実際には、の仮想デストラクタディスパッチはoperator delete、オーバーロードとは関係なく必要です。この機能はおそらく多重継承をサポートするために存在し、正しいメンバーを動的に見つけることoperator deleteは単なる副作用です。

ルールは、最も派生したオブジェクトの仮想デストラクタがを呼び出すということoperator deleteです。主な理由は、最も派生した正しいポインタとサイズを渡すことです。コンテキストによって、プログラムが正しい割り当て解除関数を動的に見つけることもできるというのは、嬉しい副作用です。

したがって、動的ディスパッチに役立つアプリケーションがある場合とない場合がありますが、deleteそれを機能させるための専用のメカニズムは絶対にありません。

簡単なデモ

struct pad {
    int x;

    virtual ~pad() {}
};

struct b {
    int x;
};

struct vb {
    int x;

    virtual ~vb() {}
};

struct d : pad, b, vb {};

void operator delete( void *p ) {
    std::cout << "free " << p << '\n';
}

int main() {
    std::cout << "With virtual destructor:\n";
    d *p = new d;
    std::cout << "allocate " << p << ", delete " << static_cast< vb * >( p ) << '\n';
    delete static_cast< vb * >( p );

    std::cout << "With plain destructor:\n";
    p = new d;
    std::cout << "allocate " << p << ", delete " << static_cast< b * >( p ) << '\n';
    delete static_cast< b * >( p );
}
于 2013-05-03T02:26:17.193 に答える