首页 > 解决方案 > 在存在 DEBUG_NEW 宏的情况下重载 operator new

问题描述

在 MFC 项目中,我使用了一个外部库TTL重载 operator new. 我的问题是我有内存泄漏,我想利用DEBUG_NEW. 但是,我只能在DEBUG_NEW注释掉的情况下编译它,否则我会收到以下错误。

下面进行演示。当 Visual Studio 项目作为带有 MFC 标头的控制台应用程序时,它是一个 MCVE 。

// The problem is when this is uncommented
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

struct HandleId
{
  HandleId() {}

  void* operator new (size_t t) {
    return HandleId::operator new(t, 0, 0, 0);
  };
  void* operator new (size_t t, int, const char* file, int line) {
    HandleId* tmp = (HandleId*)calloc(1, t);
    return tmp;
  };
  void operator delete (void* v) {
    free(v);
  }
};

namespace hed
{
  struct Node : public virtual HandleId
  {
    Node() {};
    Node(double x, double y, double z = 0.0) {}
  };
}

struct DtmNode : public hed::Node
{
  DtmNode() {};
  DtmNode(short pntRef, double x, double y, double z)
    : hed::Node(x, y, z)
  {};
};

int main()
{
  DtmNode* pNode = new DtmNode(0, 1.0, 2.0, 3.0);
  return 0;
}

DEBUG_NEW未注释上述编译失败(VS2019)。

错误 C2661: HandleId::operator new: 没有重载函数需要 3 个参数

到目前为止,我一直使用注释掉的宏。但我现在确实希望在调试版本中使用它,原因很明显,它有助于在调试期间捕获内存泄漏。DtmNode是我可以改变的课程。HandleId并且hed命名空间属于库。

我的问题:

  1. 有没有办法在DEBUG_NEW未注释的情况下编译它?
  2. 或者,有没有办法告诉在 _DEBUG 模式下DtmNode不要使用重载operator new,以便DEBUG_NEW按照“正常”使用?

标签: c++winapivisual-c++mfc

解决方案


你的第一个问题的答案是“不”。

您可以通过使用#pragma push_macro/pop_macro 选择性地取消定义 new 来编译这类东西:

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
...
int main()
{
#pragma push_macro("new")
#undef new
  DtmNode* pNode = new DtmNode(0, 1.0, 2.0, 3.0);
#pragma pop_macro("new");

  return 0;
}

它不允许您使用 MFC 的调试分配器跟踪库中的对象(为此,您必须完全替换库的分配器)。但它至少可以让你的程序在不匹配的 operator new 存在的情况下工作。


推荐阅读