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 的许多调用(创建临时字符串、扩展缓冲区等)。
因此,您可能必须想出一个聪明的方法来输出您想要输出的日志消息,而不会导致任何新删除发生,或者您必须将新删除运算符重载限制为仅你的框架。对于后者,最简单的就是把它放在一个基类中。另一种选择是使用一点 MACRO 魔法,但这仍然会很麻烦而且很麻烦。
而且,此时,如果您必须创建一个基类(对于所有库的类)来处理创建删除的日志记录(或创建一组宏以放入您创建的每个类中),您可能会最好使用构造函数/析构函数作为打印这些日志消息的地方,并保持新删除操作符不变。
1-我不想使用外部工具,需要在代码中进行。
为什么不?外部工具(如 Valgrind 之类的 VM,或通用分析器/内存跟踪器)很可能会比您做得更好,侵入性更小。