-->

Simplest way to count instances of an object

2019-02-16 07:33发布

问题:

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?

回答1:

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) {if(this != &obj) ++total_;}
   ~CountedObj() {--total_;}

   static size_t OustandingObjects() {return total_;}

private:
   static size_t total_;
};

class MyClass : private CountedObj<MyClass>
{};


回答2:

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.



回答3:

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.



回答4:

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.



回答5:

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.



回答6:

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



回答7:

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>