如何在operator new的重载中获取源位置

29
我正在我的程序中制作一个小的内存泄漏检测器,但是我的重载new和delete(以及new[]和delete[])的方法似乎没有起作用。
void* operator new (unsigned int size, const char* filename, int line)
{
    void* ptr = new void[size];
    memleakfinder.AddTrack(ptr,size,filename,line);
    return ptr;
}

我在上面的代码片段中展示了我重载new的方式。我猜这与操作符返回void*有关,但我不知道该怎么处理。

10
“doesn't seem to do anything”的意思是“似乎没有做任何事情”。你重载了运算符,但没有覆盖默认的new运算符,所以“new x”调用默认的new运算符,而“new (filename, line) x”调用了你重载的版本。 - Max Lybbert
5个回答

59

也许您可以通过一些预处理器技巧实现您想要的功能:

#include <iostream>

using namespace std;

void* operator new (size_t size, const char* filename, int line) {
    void* ptr = new char[size];
    cout << "size = " << size << " filename = " << filename << " line = " << line << endl;
    return ptr;
}

#define new new(__FILE__, __LINE__)

int main() {
    int* x = new int;
}

4
在某些平台上,size_tunsigned int类型并不等同,因此应该使用size_t而不是unsigned int吗?我认为是的。 - iggy
为什么 void* operator new (size_t size, const char* filename, int line) 的第一个参数是 size_t?如果我想重载 delete 运算符,我应该写什么? - naive231
1
@naive231:new总是以size作为其第一个参数。它接收正在分配的数据的字节大小(在这个例子中,sizeof(int))。传递给new的任何额外内容都将在次要参数中传递。 - Remy Lebeau
1
这个火炬放置是新的吗? - Jack Aidley

13
void* ptr = new void[size];

无法这样做。修复它。

永远不要尝试全局重载new/delete。可以将它们放在一个基类中并从该类派生所有对象,或者使用命名空间或模板分配器参数。为什么呢?因为如果您的程序不止一个文件并且使用STL或其他库,您将会出现问题。

下面是来自VS2005 new.cpp的new运算符的精简版本:

void * operator new(size_t size) _THROW1(_STD bad_alloc)
{       // try to allocate size bytes
   void *p;
   while ((p = malloc(size)) == 0)
    if (_callnewh(size) == 0)
     {       // report no memory
        static const std::bad_alloc nomem;
        _RAISE(nomem);
     }

     return (p);
}

8
其实,我曾有一次这样做的充分理由。我们遇到了一个编译器“问题”,其中它在跨DLL边界时以不安全的方式使用堆。解决方法是创建一个自定义版本的“new”,它使用特定命名的堆。 - T.E.D.
2
你为什么不报告错误,而选择玩火呢? - dirkgently
2
我们曾经试过使用DLL,但是我们收到的回复大致是“在我们的系统中,跨进程使用DLL效果不太好”。最终,我们停止了使用它们,但短期内这解决了问题。 - T.E.D.
7
如果您不尝试释放未由您分配的内存(反之亦然),则图书馆和其他所有内容都不会出现问题。而且STL可以使用自定义内存分配器。我们在调试版本中长时间使用自定义new/delete运算符,没有遇到任何问题。 - n0rd
8
“你为什么不报告缺陷,而是选择玩火?”如果你曾经与供应商合作过,你就会明白这个问题的答案。有些供应商比其他供应商更好,有些只会说“感谢您的错误报告 - 它将在下一个版本中修复 - 顺便说一句,您的许可证不包括下一个版本...”有些甚至会说“这不是一个缺陷,这是一个功能”,正如@T.E.D.所说的那样。 - Natalie Adams
显示剩余2条评论

13

我认为这里的问题在于你的新参数"profile"与标准运算符new不匹配,因此标准运算符没有被隐藏(因此仍在使用)。

您的new和delete的参数配置需要像这样:

void* operator new(size_t);
void operator delete(void*, size_t);

5
你是否正确地调用了重载运算符,即是否将其传递额外的参数?

4
问题出在你将两个参数添加到了重载的new运算符中。尝试以某种方式使filename和line成为全局变量(或者如果你为单个类重载new和delete,则可以使其成为成员变量)。这样应该会更好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接