27

のすべての形式を、operator new追加の引数を含むオーバーロードに置き換えるマクロを作成することは可能ですか?__FILE____LINE__

問題はoperator new、括弧の有無にかかわらずコーディングできるように思われるため、次のとおりです。

  • オブジェクトのようなマクロ:

    #define new new(__FILE__, __LINE__)
    

    次のような宣言を置き換えます。

    A* a = new A();
    
  • および関数のようなマクロ:

    #define new(A) new (A, __FILE__, __LINE__)
    

    次のような宣言を置き換えます。

    A* a = new(std::nothrow) A();
    

残念ながら、同じ識別子で2 つのマクロを宣言しようとすると、が異なっていてもエラーになるため、次の例では失敗します。

#define new new(__FILE__, __LINE__)
#define new(A) new (A, __FILE__, __LINE__) // Error: "new" already defined

私は g++ を使用しているので、可変引数マクロの構文を使用すると成功することを期待していましたが、残念ながらそうではありませんでした。以下:

#define new(...) new(__FILE__, __LINE__, ## __VA_ARGS__)

のみ一致new(xyx) A()し、一致しませんnew A()

なぜそれが不可能なのかについてのエッセイが書かれていることは知っていますが、私は非常に近いので、方法があるに違いないと感じています. 私が行方不明であることは明らかですか?

4

7 に答える 7

27

これが私が使用するものです:

new.cpp で

const char* __file__ = "unknown";
size_t __line__ = 0;

void* operator new(size_t size) {
    void *ptr = malloc(size);
    record_alloc(ptr,__file__,__line__);
    __file__ = "unknown";
    __line__ = 0;
    return ptr;
}

void delete(void *ptr)
{
   unrecord_alloc(ptr);
   free(ptr);
}

簡潔にするために、new と delete の他の定義は省略しています。「record_alloc」および「unrecord_alloc」は、ptr、line、および file を含む構造のリンクされたリストを維持する関数です)。

new.hpp で

extern const char* __file__;
extern size_t __line__;
#define new (__file__=__FILE__,__line__=__LINE__) && 0 ? NULL : new

g++ の場合、「new」は 1 回だけ展開されます。キーは「&& 0」であり、これにより false になり、実際の new が使用されます。例えば、

char *str = new char[100];

プリプロセッサによって展開されます

char *str = (__file__="somefile.c",__line__=some_number) && 0 ? NULL : new char [100];

したがって、ファイルと行番号が記録され、カスタムの新しい関数が呼び出されます。

これは、new.cpp に対応するフォームがある限り、どのフォームの new でも機能します。

于 2009-09-02T00:57:42.403 に答える
8

私の同僚である Calvin によるこの優れたブログ エントリをチェックしてください。最近、メモリ リークを診断/デバッグ ビルドでメモリ リークを割り当てた行に関連付けるために、このタイプの修正を有効にしたいという状況がありました。面白い裏技です

https://docs.microsoft.com/en-us/archive/blogs/calvin_hsia/overload-operator-new-to-detect-memory-leaks

于 2009-03-06T16:40:40.033 に答える
2

次のライブラリ「nvwa」は、新規/削除メモリ リークを追跡するのに非常に役立ちます。例としてファイル「debug_new」を参照するか、「そのまま」使用してください。

于 2009-03-10T12:02:35.363 に答える
1

できることは、演算子 new をオーバーロードし、そこでスタック トレースを取得し (プラットフォーム固有)、スタック情報を使用して new が呼び出された場所から推測することです。

于 2009-04-06T20:43:31.310 に答える
1

使用しているコンパイラはわかりませんが、少なくとも GCC では、new をオーバーライドして呼び出し元アドレスをログに記録し、後で addr2line を使用してそれをファイル/行情報に変換できます (または、BFD ライブラリを使用してすぐに実行します)。

于 2009-03-06T16:40:59.690 に答える
-2

いいえ、仕方がありません。

の古き良き時代にはこれを行うことができましたmalloc()/free()が、new.

演算子をグローバルにオーバーライドすることでメモリ アロケータを置き換えることができnewますが、話している特殊変数を挿入することはできません。

于 2009-03-06T16:31:50.197 に答える