2- グローバル new 演算子をオーバーロードした場合、クラスまたは他のメンバーの名前にアクセスするにはどうすればよいですか?
できません。new 演算子と delete 演算子は単純な関数呼び出しではないことを理解する必要があります。実際には、次のような構文MyClass* p = new MyClass();
は次と同等です。
MyClass* p = (MyClass*) malloc(sizeof(MyClass)); // A) allocate the memory.
new(p) MyClass(); // B) call constructor (via placement-new syntax (to illustrate)).
adelete p;
は次と同等です。
p->~MyClass(); // C) call destructor.
free(p); // D) free the memory.
new-delete 演算子をオーバーロードする場合、コンパイラが実際にオーバーロードできるのは、それぞれステップ A) と D) だけです。つまり、カスタム new 演算子の本体に到達すると、オブジェクトはまだ作成されていないため、メモリ内のアドレスを除いて、オブジェクトに関する情報 (クラス、名前など) にアクセスしたり出力したりすることはできません。 、オーバーロードされた new で印刷できます。同様に、カスタムの削除演算子に到達するまでに、オブジェクトは破棄されており、特に仮想関数または文字列値を使用する場合は、そのメモリにまだぶら下がっている可能性のある情報を使用しようとする試みは未定義の動作です。
実際、このアプローチでできる最善の方法は、new 演算子で作成されたポインターを出力し、delete 演算子によって削除されたポインターを出力することです。
また、他の人が述べたように、new-delete 演算子内で操作を行うときは、無限再帰に注意する必要があります。たとえば、次のような単純な行です。
std::cout << "Created pointer: " << reinterpret_cast<std::size_t>(p) << std::endl;
ほとんどの場合、new と delete の多くの呼び出しが発生します (一時的な文字列の作成、バッファーの拡張など)。
したがって、おそらく、出力したいログ メッセージを new-delete を発生させずに出力する賢い方法を考え出すか、new-delete 演算子のオーバーロードを次のクラスのみに制限する必要があります。あなたのフレームワーク。後者の場合、最も簡単な方法は、基本クラスに配置することです。もう 1 つのオプションは、MACRO マジックを少し使用することですが、これは依然として煩雑で扱いにくいものです。
そして、この時点で、この作成と削除のロギングを処理する基本クラスを (すべてのライブラリのクラスに対して) 作成する必要がある場合 (または、作成する各クラスに配置する一連の MACRO を作成する必要がある場合)、次のようにします。これらのログメッセージを出力する場所として代わりにコンストラクター/デストラクタを使用し、new-delete 演算子はそのままにしておきます。
1- 外部ツールを使用したくないので、コード内で行う必要があります。
なぜだめですか?外部ツール (Valgrind のような VM、または一般的なプロファイラー / メモリ トレーサー) は、あなたよりもはるかに優れた、邪魔にならない仕事をする可能性が非常に高いです。