With regard to the following code. I have only included Memory.h in ClassA.cpp, but ClassB.cpp still seems to be able to see it. How do i make it so that ClassB does not use the operator new in Memory.h, but the usual one?

Am am I right in thinking it has something to do with external linkage? But in that case, wouldnt i still have to declare an extern func signature for new in ClassB.cpp?

Basically, Im wanting it so that my overide of operator delete is only used in the source files I include Memory.h in.

//Memory.h

#pragma once

#include <iostream>

void* operator new ( size_t size );
void operator delete ( void* p, int size );
//Memory.cpp
#include "Memory.h"

void* operator new ( size_t size )
{
	std::cout << " Allocating " << size << " bytes" << std::endl;
	return 0;
}

void operator delete ( void* p, int size )
{
	std::cout << " Deallocating " << size << " bytes" << std::endl;
}
//ClassA.h

#pragma once

class ClassA
{
public:
	void Hello();
};
//ClassA.cpp

#include "ClassA.h"
#include "Memory.h"

void ClassA::Hello(){
	new char();
}
//ClassB.h

#pragma once

class ClassB
{
public:
	void Hello();
};
//ClassB.cpp

#include "ClassB.h"

void ClassB::Hello(){
	new char();
}

Dani AI

Generated

Summary and practical fixes, tied to the existing replies.

As pointed out, a global replacement of operator new / operator delete is a program-wide replacement: the compiler emits calls that resolve at link time, so defining a matching global operator affects every translation unit that ends up in the final executable. That is why ClassB sees the override even though it doesn’t #include the header. See cppreference — operator new for the rules and replacement behavior.

Two correctness notes visible in the posted code:

  • A global operator new must either return usable storage or throw std::bad_alloc; returning 0 is not correct for the normal throwing form. Use std::malloc and throw on failure, or implement the nothrow overload if null is expected.
  • The delete signature should match the standard overloads. Modern C++ also has the sized deallocation signature that takes std::size_t; using int is the wrong type and will not behave as intended across compilers.

If selective tracking is required, prefer one of these safe patterns instead of trying to scope a global operator:

  • Per-class overloads (only instances of that class use the custom allocator):
class Tracked {
public:
  static void* operator new(std::size_t n) {
    // log, allocate, or forward to ::operator new
    return ::operator new(n);
  }
  static void operator delete(void* p) noexcept {
    ::operator delete(p);
  }
};
  • Explicit allocator/wrapper objects or custom allocators for containers (as suggested with a tracked heap).
  • A scoped macro/placement-new trick can be made to only affect chosen translation units, but it is fragile (breaks genuine placement-new uses and third-party headers).

Also consider existing tools (Valgrind, ASan) for allocation tracking instead of globally replacing operators. ’s observation about different behaviors for class vs global overloads aligns with preferring class-level or explicit allocators for selective tracking.

Recommended Answers

All 7 Replies

>Am am I right in thinking it has something to do with external linkage?
Something like that. The following operators are implicitly declared in every file:

void *operator new ( size_t bytes );
void *operator new[] ( size_t bytes );
void operator delete ( void* );
void operator delete[] ( void* );

If you override them with a matching definition, all uses will refer to your definition, not the implementation's.

>Basically, Im wanting it so that my overide of operator delete
>is only used in the source files I include Memory.h in.

I strongly recommend not overriding the global new and delete operators. It's tricky to get right and easy to be surprised. Why exactly do you need this behavior?

I just wanted to some tracking, such as how memory is allocated, when and how often

If you don't want to track allocations globally (as in everywhere), then you'd be better off only overloading new and delete for specific classes, or using an allocation class that makes your tracking needs explicit:

#include <cstddef>
#include <iostream>

namespace jsw {
  namespace memory {
    class tracked_heap {
      // Single object counters
      int _n_soalloc;
      int _n_sofree;

      // Dynamic array counters
      int _n_daalloc;
      int _n_dafree;
    public:
      tracked_heap()
        : _n_soalloc ( 0 ), _n_sofree ( 0 ),
          _n_daalloc ( 0 ), _n_dafree ( 0 )
      {}

      int single_alloc() const { return _n_soalloc; }
      int single_free() const { return _n_sofree; }
      int array_alloc() const { return _n_daalloc; }
      int array_free() const { return _n_dafree; }

      template <typename T>
      T *alloc ( std::size_t n = 0 )
      {
        T *p = 0;

        if ( n <= 0 ) {
          p = new T;
          ++_n_soalloc;
        }
        else {
          p = new T[n];
          ++_n_daalloc;
        }

        return p;
      }

      void free ( void *p, std::size_t n = 0 )
      {
        if ( n <= 0 ) {
          delete p;
          ++_n_sofree;
        }
        else {
          delete[] p;
          ++_n_dafree;
        }
      }
    };
  }
}

namespace {
  jsw::memory::tracked_heap heap;
}

int main()
{
  std::cout<<'('<<heap.single_alloc() <<','<< heap.array_alloc() <<")\n"
           <<'('<<heap.single_free() <<','<< heap.array_free() <<")\n\n";

  int *p = heap.alloc<int>();
  int *q = heap.alloc<int> ( 5 );

  std::cout<<'('<<heap.single_alloc() <<','<< heap.array_alloc() <<")\n"
           <<'('<<heap.single_free() <<','<< heap.array_free() <<")\n\n";

  heap.free ( p );
  heap.free ( q, 5 );

  std::cout<<'('<<heap.single_alloc() <<','<< heap.array_alloc() <<")\n"
           <<'('<<heap.single_free() <<','<< heap.array_free() <<")\n\n";

  bool so_leak = heap.single_alloc() - heap.single_free() != 0;
  bool da_leak = heap.array_alloc() - heap.array_free() != 0;

  std::cout<< std::boolalpha 
           <<"Single Object Leaks: "<< so_leak <<'\n'
           <<"Dynamic Array Leaks: "<< so_leak <<'\n';
}

Thanks for the reply. Yours seems like an interesting way to go about it. But it not so much that I dont want to track allocations globally, ... I do. I just dont want to track them in certain source files.

>But it not so much that I dont want to track allocations globally, ... I
>do. I just dont want to track them in certain source files.

You realize that those two statements are contradictory, right? If you want to do it globally, that means every file, the whole program. If you don't want to do it globally, which is clearly the case, you can override (or not) the global operators and then use an alternative strategy (such as the one I suggested) for those "certain" files.

If you override them with a matching definition, all uses will refer to your definition, not the implementation's.

in fact, both implicit & explicit implemations for new & delete are called when you use them. new & delete are strange operators. I have a few examples about the order of calling for implicit & explicit implementation. but I'm too lazy to try to find them ;)
but I'll post if I find...

I looked at my examples. they were about overloading new & delete operators inside a class. sorry I was wrong :$.
there are cases that someone needs to edit or delete his posts. but I don't arg..

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.