【问题标题】:Overloaded operator new in the presence of DEBUG_NEW macro在存在 DEBUG_NEW 宏的情况下重载 operator new
【发布时间】:2020-03-10 15:00:21
【问题描述】:

在 MFC 项目中,我使用外部库 TTLoverloads operator new。我的问题是我有内存泄漏,我想利用DEBUG_NEW 给出的诊断。但是我只能用 DEBUG_NEW 注释掉来编译它,否则我会得到下面的错误。

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

// 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 是我可以更改的课程。 HandleIdhed 命名空间属于该库。

我的问题:

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

【问题讨论】:

  • 用不会泄漏的东西替换DtmNode* pNode 不是很合理吗?比如std::unique_ptrstd::shared_ptr

标签: c++ winapi visual-c++ mfc


【解决方案1】:

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

您可以通过使用 #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 存在的情况下工作。

【讨论】:

  • 请记住,定义与关键字 (new) 同名的宏会导致未定义的行为。
  • 它可能是未定义的,但视觉 c++(MFC 的存在绝大多数表明使用它)在这种情况下表现合理。
  • 是的,MFC实现和使用在定义该宏时有效。很可能当您定义一个类似的宏时,您的代码大部分都可以工作,如果您小心地只以与在 MFC 中使用相同的方式使用该宏,并且始终完全使用它与在 MFC 中使用的方式相同。这在 MFC 中是一个坏主意,在任何其他代码中都是一个坏主意。
  • @SornelHaetir 在您的回答中,在 struct HandleId 的声明中使用编译指示不是更有意义,其中运算符声明中的 new 关键字不得重新映射,而不是在main 的主体,其中重新映射的 new 可以并打算使用?
  • 根据您的第一句话接受这一点。最后我发现了没有 MFC 帮助的内存泄漏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多