0

In an MFC project I'm using an external library TTL that overloads operator new. My problem is that I have a memory leak and I'd like to make use of the diagnostics given by DEBUG_NEW. However I'm only able to compile this with DEBUG_NEW commented-out else I get the error below.

The following demonstrates it. It is an MCVE when the Visual Studio project is made as a console application with MFC headers.

// 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;
}

With DEBUG_NEW uncommented the above compilation fails (VS2019) with.

error C2661: HandleId::operator new: no overloaded function takes 3 arguments

Up to now I've lived with the macro commented-out. But I now do want it in debug builds for the obvious reason of helping catch memory leaks during debugging. DtmNode is my class which I can change. HandleId and the hed namespace belong to the library.

My question:

  1. Is there a way to compile this with DEBUG_NEW uncommented?
  2. Alternatively, is there any way to tell DtmNode not to use the overloaded operator new when in _DEBUG mode so that the DEBUG_NEW is used as per "normal"?
acraig5075
  • 10,588
  • 3
  • 31
  • 50
  • Wouldn't it be reasonable to replace `DtmNode* pNode` with something, that won't leak? Like a `std::unique_ptr` or `std::shared_ptr`. – IInspectable Mar 10 '20 at 15:45

1 Answers1

0

The answer to your first question is 'no'.

You can make this sort of thing compile by selectively undefining new using #pragma push_macro/pop_macro:

#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;
}

It won't allow you to track objects from the library using MFC's debug allocator (you would have to completely replace the library's allocator for that). But it will at least allow your program to work in the presence of a non-matching operator new.

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
  • Keep in mind that defining a macro with the same name as a keyword (`new`) results in undefined behavior. – Pete Becker Mar 10 '20 at 16:58
  • It might be undefined but visual c++ (which the presence of MFC overwhelmingly indicates use of) behaves reasonably in this circumstance. – SoronelHaetir Mar 10 '20 at 18:00
  • Yes, the **implementation and use** of **MFC** works when that macro is defined. It may well be that your code will mostly work when you define a similar macro, if you are careful to only use that macro in the same way that it's used in MFC, and to **always** use it in exactly the same way as it's used in MFC. It was a bad idea in MFC, and it's a bad idea in any other code. – Pete Becker Mar 10 '20 at 18:40
  • 1
    @SoronelHaetir in your answer, doesn't it make more sense to use the pragmas around the declaration of `struct HandleId` where the `new` keyword in the operator declarations must not be remapped, rather than in the body of `main` where a remapped `new` is OK and intended to be used? – Remy Lebeau Mar 10 '20 at 19:39
  • Accepting this on the basis of your first sentence. In the end I found the memory leak without the MFC assistance. – acraig5075 Mar 12 '20 at 08:57