20

I would like to know the exact number of instances of certain objects allocated at certain point of execution. Mostly for hunting possible memory leaks(I mostly use RAII, almost no new, but still I could forget .clear() on vector before adding new elements or something similar). Ofc I could have an

atomic<int> cntMyObject;

that I -- in destructor, ++ increase in constructor, cpy constructor(I hope I covered everything :)). But that is hardcoding for every class. And it is not simple do disable it in "Release" mode. So is there any simple elegant way that can be easily disabled to count object instances?

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • 2
    Why not to use a profile to find memory leaks?... –  Aug 17 '11 at 18:34
  • 2
    Not the assignment operator -- it doesn't change the number of existing objects of the type, just alters the value of one of them. – Steve Jessop Aug 17 '11 at 19:16
  • 2
    As much as I find the idea of adding a global object counter interesting, I'd say that for your practical problem of eliminating memory errors, running your program through Valgrind would be a much more approachable solution, with more meaningful messages, too. – Kerrek SB Aug 17 '11 at 19:21
  • If you think something like google HEAPProfiler-it is nice, but once I messed up STL stuff(non thread safe updates)and it didnt detect leaks(it did help me find them since i noticed the circles are getting bigger for reloading same stuff). Also I dont know how to focus on certain class in HeapProfiler, I only know to generate "entire program mem usage". – NoSenseEtAl Aug 17 '11 at 19:26
  • Are you prepared to accept compiler specific solutions? I can offer a non intrusive gcc one and there's a similar function for msvc too. – Flexo Aug 20 '11 at 15:57
  • Yes, Im using gcc(g++), ofc I always prefer "in standard" solutions – NoSenseEtAl Aug 21 '11 at 21:41
  • Using profiler is not the answer here. As the asker mentioned forgetting a vector.clear() will always be a problem. Otherwise there wouldn't be memory leaks in Java programs. It's not the typical C++ leaks but it is an important problem and it needs a total different tool to solve it then valgrind etc. – Lothar Aug 02 '16 at 16:34

9 Answers9

34

Have a "counted object" class that does the proper reference counting in its constructor(s) and destructor, then derive your objects that you want to track from it. You can then use the curiously recurring template pattern to get distinct counts for any object types you wish to track.

// warning: pseudo code

template <class Obj>
class CountedObj
{
public:
   CountedObj() {++total_;}
   CountedObj(const CountedObj& obj) {++total_;}
   ~CountedObj() {--total_;}

   static size_t OustandingObjects() {return total_;}

private:
   static size_t total_;
};

class MyClass : private CountedObj<MyClass>
{};
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
Chad
  • 18,706
  • 4
  • 46
  • 63
  • 4
    You shouldn't really need the same-object check in the copy ctor, since it's not generally valid to copy-construct an object from itself, so anyone doing that is already playing silly games. Doesn't do any harm, though. Insert atomicity or locks to taste, but the questioner already knows about that. – Steve Jessop Aug 17 '11 at 19:15
  • I was hoping for something that doesnt require permanent code change, but this is nice solution. – NoSenseEtAl Aug 17 '11 at 19:22
  • No permanent code change? What do you mean? You can just surround the increment/decrement code with `#ifdef NDEBUG` which relies on the `assert()` define. Or you can use a *Trait* on a boolean, to simply enable or disable the code for Debug or Production. But thats not "simple" anymore. If you are interested anyway, I can paste a piece of sample code here. All you then are needed to do is to define either `static const bool debug = true` or `false`, and yo provi two template specializations for `CountedObj`: One completely empty, one with debug code in there. – towi Aug 20 '11 at 16:08
  • Doh, Im such a noob, all clear now. BTW do you know what is the simplest way to make the logging of the counters also contained in the base class? I thought about launching a thread first time when class is created, and having that thread to do the counting. – NoSenseEtAl Aug 21 '11 at 21:51
  • If using windows you'll get in trouble if your objects are in several different dlls because of the way the static variables are managed, one copy by dll and one copy in the executable program. – Pedro Ferreira Aug 23 '11 at 13:36
  • 4
    @NoSenseEtAl : It makes NoSenseAtAll to have a thread that is doing counting. If you use the CountObj, and make it the base class of the classes whose object you want to keep track of then, within the context of the thread in which the object was instantiated, the count will be incremented. – Ajeet Ganga Aug 25 '11 at 05:08
  • Comparing for this != &obj is really not needed in the copy ctor since this is alway a new object. – Simon Aug 25 '11 at 14:19
  • @Ajeet- sorry, last word should be logging, not counting. – NoSenseEtAl Aug 25 '11 at 22:05
  • `if(this != &obj)` -- how could this **ever** evaluate to false? – ildjarn Aug 31 '11 at 19:42
  • @Chad : Well, the rest of the code was perfect, so I thought maybe I was just missing something. :-] – ildjarn Aug 31 '11 at 20:13
  • What about the assignment operator? Shouldn't an assignment also increment `total_`? – Flow Feb 21 '14 at 13:16
  • 1
    Assignment generally doesn't increase the number of objects (copy assignment, via the copy constructor does). – Chad Feb 21 '14 at 15:17
  • I've took liberty of editing out `this != &obj`, since `MyClass x(x);` is legal if the reference is not actually accessed (and if it is, you get UB anyway). – HolyBlackCat Jan 20 '23 at 14:34
12

you can apply this approach

#ifdef DEBUG

class ObjectCount {
    static int count;
  protected:
    ObjectCount() {
        count++;
    }
  public:
    void static showCount() {
        cout << count;
    }
};

int ObjectCount::count = 0;


class Employee : public ObjectCount {
#else
class Employee {
#endif
  public:
    Employee(){}
    Employee(const Employee & emp) {

    }
};

at DEBUG mode, invoking of ObjectCount::showCount() method will return count of object(s) created.

Neel Basu
  • 12,638
  • 12
  • 82
  • 146
sukumar
  • 377
  • 1
  • 6
9

Better off to use memory profiling & leak detection tools like Valgrind or Rational Purify.

If you can't and want to implement your own mechanism then,

You should overload the new and delete operators for your class and then implement the memory diagnostic in them.

Have a look at this C++ FAQ answer to know how to do that and what precautions you should take.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • Doesn't the FAQ entry totally forget to mention the requirement that operator-new is mandated by the standard to contain an infinite loop calling the new-handler in case of failure? – Kerrek SB Aug 17 '11 at 18:40
  • @Kerrek SB: *Infinite Loop?* I am not sure I understand, Isn't new supposed to just throw `std::bad_alloc` in case of failure? – Alok Save Aug 17 '11 at 18:47
  • There should be some sort of infinite loop, since the handlers may install futher handlers. Either your new handler provides memory and you break, or there is no more new handler and you throw. – Kerrek SB Aug 17 '11 at 18:52
  • Hm, maybe it's not actually in the standard. 3.7.4.1.3 only says that you "may" call the new handler. Scott Meyers #49 says you should loop and call new handlers. – Kerrek SB Aug 17 '11 at 18:56
  • @Kerrek SB: Is this specified by the Standard or an implementation detail? If it is Standard specified(I am not aware of it but it would be interesting if it so) You can discuss it with Sbi in C++ Lounge or add a comment on the FAQ answer,(if you guys do have a conversation, please do add a link here so i can followup as well, I am in a different time zone & already well past midnight for me now, So can't stay back :() – Alok Save Aug 17 '11 at 18:57
3

This is a sort of working example of something similar: http://www.almostinfinite.com/memtrack.html (just copy the code at the end of the page and put it in Memtrack.h, and then run TrackListMemoryUsage() or one of the other functions to see diagnostics)

It overrides operator new and does some arcane macro stuff to make it 'stamp' each allocation with information that allow it to count how many instances of an object and how much memory they're usingusing. It's not perfect though, the macros they use break down under certain conditions. If you decide to try this out make sure to include it after any standard headers.

Alex
  • 14,973
  • 13
  • 59
  • 94
2

Without knowing your code and your requirements, I see 2 reasonable options:

a) Use boost::shared_ptr. It has the atomic reference counts you suggested built in and takes care of your memory management (so that you'd never actually care to look at the count). Its reference count is available through the use_count() member.

b) If the implications of a), like dealing with pointers and having shared_ptrs everywhere, or possible performance overhead, are not acceptable for you, I'd suggest to simply use available tools for memory leak detection (e.g. Valgrind, see above) that'll report your loose objects at program exit. And there's no need to use intrusive helper classes for (anyway debug-only) tracking object counts, that just mess up your code, IMHO.

Neel Basu
  • 12,638
  • 12
  • 82
  • 146
awx
  • 126
  • 1
  • 4
1

My approach, which outputs leakage count to Debug Output (via the DebugPrint function implemented in our code base, replace that call with your own...)

#include <typeinfo> 
#include <string.h>
class CountedObjImpl
{
public:
        CountedObjImpl(const char* className) : mClassName(className) {}
        ~CountedObjImpl()
        {
                DebugPrint(_T("**##** Leakage count for %hs: %Iu\n"), mClassName.c_str(), mInstanceCount);
        }
        size_t& GetCounter() 
        {
                return mInstanceCount;
        }

private:
        size_t mInstanceCount = 0;
        std::string mClassName;
};

template <class Obj>
class CountedObj
{
public:
        CountedObj() { GetCounter()++; }
        CountedObj(const CountedObj& obj) { GetCounter()++; }
        ~CountedObj() { GetCounter()--; }

        static size_t OustandingObjects() { return GetCounter(); }

private:
        size_t& GetCounter()
        {
                static CountedObjImpl mCountedObjImpl(typeid(Obj).name());
                return mCountedObjImpl.GetCounter();
        }
};

Example usage:

class PostLoadInfoPostLoadCB : public PostLoadCallback, private CountedObj<PostLoadInfoPostLoadCB>
Larry
  • 11
  • 1
1

Adding counters to individual classes was discussed in some of the answers. However, it requires to pick the classes to have counted and modify them in one way or the other. The assumption in the following is, you are adding such counters to find bugs where more objects of certain classes are kept alive than expected.

To shortly recap some things mentioned already: For real memory leaks, certainly there is valgrind:memcheck and the leak sanitizers. However, for other scenarios without real leaks they do not help (uncleared vectors, map entries with keys never accessed, cycles of shared_ptrs, ...).

But, since this was not mentioned: In the valgrind tool suite there is also massif, which can provide you with the information about all pieces of allocated memory and where they were allocated. However, let's assume that valgrind:massif is also not an option for you, and you truly want instance counts.

For the purpose of occasional bug hunting - if you are open for some hackish solution and if the above options don't work - you might consider the following: Nowadays, many objects on the heap are effectively held by smart pointers. This could be the smart pointer classes from the standard library, or the smart pointer classes of the respective helper libraries you use. The trick is then the following (picking the shared_ptr as an example): You can get instance counters for many classes at once by patching the shared_ptr implementation, namely by adding instance counts to the shared_ptr class. Then, for some class Foo, the counter belonging to shared_ptr<Foo> will give you an indication of the number of instances of class Foo.

Certainly, it is not quite as accurate as adding the counters to the respective classes directly (instances referenced only by raw pointers are not counted), but possibly it is accurate enough for your case. And, certainly, this is not about changing the smart pointer classes permanently - only during the bug hunting. At least, the smart pointer implementations are not too complex, so patching them is simple.

Dirk Herrmann
  • 5,550
  • 1
  • 21
  • 47
1

We used to have the solution of a base class with internal counter and derive from it, but we changed it all into boost::shared_ptr, it keeps a reference counter and it cleans up memory for you. The boost smart pointer family is quite useful: boost smart pointers

Pedro Ferreira
  • 852
  • 9
  • 23
-1

This approach is much simpler than the rest of the solutions here.

Make a variable for the count and make it static. Increase that variable by +1 inside the constructor and decrease it by -1 inside the destructor.

Make sure you initialize the variable (it cannot be initialized inside the header because its static).

.h

// Pseudo code warning
class MyObject
{
   MyObject();
   ~MyObject();
   static int totalObjects;
}

.cpp

int MyObject::totalObjects = 0;

MyObject::MyObject()
{
   ++totalObjects;
}

MyObject::~MyObject()
{
   --totalObjects;
}

For every new instance you make, the constructor is called and totalObjects automatically grows by 1.

Horizonik
  • 21
  • 6
  • You must also instrument the copy constructor. The constructors and the destructor must be declared in the header. If you fix this, this is essentially the same as the accepted answer. – HolyBlackCat Jan 20 '23 at 14:32