4

I'd like to be able to count instances of classes that belong in the same class hierarchy.

For example, let's say I have this:

class A;
class B: public A;
class C: public B;

and then I have this code

A* tempA = new A;
B* tempB = new B;
C* tempC = new C;
C* tempC2 = new C;

printf(tempA->GetInstancesCount());
printf(tempB->GetInstancesCount());
printf(tempC->GetInstancesCount());

the result of that should print
1
1
2

The counting, ideally, should be done internally. Each class, and not some kind of manager, should know how many instances it has.

Any ideas?

Thanks!

djcouchycouch
  • 12,724
  • 13
  • 69
  • 108

10 Answers10

6

There is a problem with proposed solutions: when you create B you A constructor will be called automatically and thus increment count of A.

class A
{
public:
    A(bool doCount = true)
    {
        if (doCount)
            ++instanceCount_;
    }

    static std::size_t GetInstanceCount()
    {
        return instanceCount_;
    }

    virtual ~A(){}
private:
    static std::size_t instanceCount_;
};

class B: public A
{
public:
    B(bool doCount = true):A(false)
    {
        if (doCount)
            ++instanceCount_;
    }

    static std::size_t GetInstanceCount()
    {
        return instanceCount_;
    }
private:
    static std::size_t instanceCount_;
};

std::size_t A::instanceCount_ = 0;
std::size_t B::instanceCount_ = 0;
Mykola Golubyev
  • 57,943
  • 15
  • 89
  • 102
4

Directly off my head:

  • Create an integer static field in each class. Watch out for integer overflow.
  • Initialize it to 0 in an emulated static constructor.
  • Increment it at each (nonstatic) constructor body. Decrement it in the destructor.
  • GetInstancesCount() is a static function that returns the value of your integer static field.

Note: See Mykola's comments. This would print 4 for A, 3 for B and 2 for C i.e. it would count one instance of B as "one A and one B", and one C as "one A, one B and one C". Which is in a way true, but is not what the question asks for. In other words, my answer is wrong :)

Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
3

A bit of the "Curiously reoccurring template pattern".

template<typename P>
class Counter
{
    public: Counter(bool inc)
        :m_wasInc(inc)
    {
        if (m_wasInc)
        {   getCount()++;}
    }
           ~Counter()
    {
        if (m_wasInc)
        {   getCount()--;}
    }
    static std::size_t GetInstancesCount()
    {
         return getCount();
    }
    private:
       bool m_wasInc;
       /*
        * Alternatively this can be a static member variable.
        * I just used a function because this means I do not need to declare
        * the variable for each type class. The down size is that it becomes
        * more complex if used in the presence of a DLL's.
        *
        * But that is way easy to change. See Alternative Version below.
        */
       static std::size_t& getCount()
       {
           static std::size_t count = 0;
           return count;
       }
};

class A: public Counter<A>
{
    public: A(bool count = true): Counter<A>(count){}
};

class B: public A,Counter<B>
{
    public: B(bool count = true): A(false), Counter<B>(count){}
};

class C: public A, Counter<C>
{
    public: C(bool count = true): A(false), Counter<C>(count){}
};

template<typename P>
class CounterAlt
{
    public: CounterAlt()
    {    ++count;
    }
    static std::size_t GetInstancesCount()
    {
         return count;
    }
    private:
       static std::size_t count;
};

class D: public CounterAlt<D>
{
};
std::size_t CounterAlt<D>::count = 0;
Martin York
  • 257,169
  • 86
  • 333
  • 562
2

Use a static member variable for each class.

struct A {
    A() { mInstances++; }
    ~A() { mInstances--; }
    static size_t mInstances;
    static size_t GetInstancesCount() { return mInstances; }
};

size_t A::mInstances;

int main() {
    A* a = new A;
    A* aa = new A;
    cout << A::GetInstancesCount() << endl;
    delete a;
    delete aa;
    cout << A::GetInstancesCount() << endl;
    return 0;
}
dirkgently
  • 108,024
  • 16
  • 131
  • 187
1

A very crude way would be:

class A
{
public:
    static int m_instanceCount;
    A(bool derivedInstance = false)
    {
        if(! derivedInstance)
        {
            ++m_instanceCount;
        }
    }
    virtual ~A()
    {
        --m_instanceCount;
    }
    virtual int GetInstanceCount()
    {
        return m_instanceCount;
    }
};

int A::m_instanceCount = 0;


class B : public A
{
public:
    static int m_instanceCount;
    B(bool derivedInstance = false): A(true) 
    {
        if(! derivedInstance)
        {
            ++m_instanceCount;
        }
    }
    virtual ~B()
    {
        --m_instanceCount;
    }
    virtual int GetInstanceCount()
    {
        return m_instanceCount;
    }
};

int B::m_instanceCount = 0;


class C : public B
{
public:
    static int m_instanceCount;
    C(): B(true) {++m_instanceCount;}
    virtual ~C()
    {
        --m_instanceCount;
    }
    virtual int GetInstanceCount()
    {
        return m_instanceCount;
    }
};

int C::m_instanceCount = 0;




void main(int argc,char *argv[])
{   
    A* p1 = new A;
    B* p2 = new B;
    C* p3 = new C;
    C* p4 = new C;
    A* p5 = new A;

    delete p5;

    std::cout<<p1->GetInstanceCount()<<"\n";
    std::cout<<p2->GetInstanceCount()<<"\n";
    std::cout<<p3->GetInstanceCount()<<"\n";
}   
Naveen
  • 74,600
  • 47
  • 176
  • 233
1

This is a simple counter I use each so often for debugging:

// counter.hpp
#ifndef COUNTER_HPP
#define COUNTER_HPP

template <typename T>
class Counter
{
public:
    Counter( bool do_count = true ) : counted(do_count) 
    { if ( counted ) get_count()++; }
    ~Counter() { if (counted) --count_; }

    static unsigned long count() { return count_; }
    static unsigned long& get_count() { 
       static unsigned long count=0;
       return count;
    }
private:
    bool do_count;
};
#endif 

The usage is simple, just inherit from it:

class BaseClass : public Counter<BaseClass>
{
public:
   explicit BaseClass( bool do_count = true ) 
      : Counter<BaseClass>( do_count )
   {}
};
class DerivedClass : public BaseClass, Counter<DerivedClass>
{
public:
   explicit DerivedClass( bool do_count = true )
      : BaseClass(false), Counter<DerivedClass>(do_count)
   {}
};

User code will call a parameterless constructor:

int main() {
   BaseClass b; // will call Counter<BaseClass>(true)
   DerivedClass d; // will call Counter<BaseClass>(false), Counter<DerivedClass>(true)
}
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • +1. But as Martin York says, you will also need to add a definition for Counter::count_ for each T that you use. – j_random_hacker Apr 21 '09 at 14:19
  • Not with the current implementation. The counter is an static function variable. It will be created on the first call to get_counter() that happens during construction of the first counted element of the class. – David Rodríguez - dribeas Apr 21 '09 at 14:43
  • OK, I guess you mean "Not with the new implementation" -- you must have changed the code around the same time as I commented. Yes, the latest version doesn't require per-type definitions -- much nicer. – j_random_hacker Apr 22 '09 at 11:30
1

One way to get around the double-counting when counting objects in the constructor is to count the objects at the point of need, rather than in the constructor, using RTTI. This is minimally intrusive:

#include <vector>
#include <typeinfo>
#include <iostream>
#include <functional>


class A
{

public:

    A();
    virtual ~A() { }

};

class B: public A
{

public:

    virtual ~B() { }
};

class C: public B
{

public:

    virtual ~C() { }

};

template<class T>
struct TypeIdsEqual: public std::binary_function<T, T, bool>
{
    bool operator() (const T& obj1, const T& obj2) const
    {
        return typeid(*obj1) == typeid(*obj2);
    }
};

struct Counter
{
    static std::vector<A*> objects;

    static void add(A* obj)
    {
        objects.push_back(obj);
    }

    static int count(A* obj)
    {
        return std::count_if(objects.begin(), objects.end(),
                             std::bind1st(TypeIdsEqual<A*>(), obj));
    }

};

std::vector<A*> Counter::objects;

// One intrusive line in the base class constructor.  None in derived classes...
A::A()
{
    Counter::add(this);
}

int main(int *argc, char* argv[])
{
    A* a  = new A;
    B* b  = new B;
    C* c  = new C;
    C* c2 = new C;
    std::cout << Counter::count(*a) << std::endl;  // Output: 1
    std::cout << Counter::count(*b) << std::endl;  // Output: 1
    std::cout << Counter::count(*c) << std::endl;  // Output: 2
}
maxaposteriori
  • 7,267
  • 4
  • 28
  • 25
0

Create the classes through a factory so the factory will be able to keep track of how many have been created.

Not as clean as just calling new on the class but it may do what you need.

James Black
  • 41,583
  • 10
  • 86
  • 166
0

The current solutions all seem to count in constructors, and therefore also count in constructors of base type. (except Mykola, but that solution has an implicit conversion from bool - bad) This double-counting wasn't desired. The tricky part, though, is that during the construction of a derived type, the object temporary has intermediate base types. And with virtual base classes, this situation is even worse. In that case, the intermediate type isn't even well-defined.

Ignoring such transients, there are a few solutions to the double-counting:

  • Use a flag to disable counting
  • Use a protected base class constructor which doesn't count
  • Decrease the instance count of your base classes in derived constructors '*(this->base::count)--`
  • Keep the counts in a dedicated virtual base class.

The latter option (virtual base class) is probably the nicest; the compiler will enforce it's initialized once and only once, from the final ctor.

class counter {
    template<typename T> struct perTypeCounter { static int count =  0; }
    int* count; // Points to perTypeCounter<MostDerived>::count

    protected:
    template<typename MostDerived> counter(MostDerived*) 
    {
        count = &perTypeCounter<MostDerived>::count;
        ++*count;
    }
    ~counter() { --*count; }
};
MSalters
  • 173,980
  • 10
  • 155
  • 350
0

You can use virtual inheritance to force the counting base class constructor to be called by every super class constructor and only that constructor. This fixes the double counting problem. Then use RTTI for the rest:

#include <map>
#include <typeinfo>
#include <iostream>

struct type_info_less
{
    bool operator() (const std::type_info * t1, const std::type_info * t2) {
        return t1->before(*t2);
    }
};

struct InstCounter
{
    typedef std::map<const std::type_info *, size_t, type_info_less> CountMap;
    static CountMap countMap_;
    const std::type_info * my_type_;

    InstCounter(const std::type_info & type) : my_type_(&type){
        ++countMap_[my_type_];
    }

    ~InstCounter() {
        --countMap_[my_type_];
    }

    static size_t getCount(const std::type_info & type) {
        return countMap_[&type];
    }

    size_t getCount() {
        return countMap_[my_type_];
    }
};

InstCounter::CountMap InstCounter::countMap_;

struct A : public virtual InstCounter
{
    A() : InstCounter(typeid(A)) {}
};

struct B : public A
{
    B() : InstCounter(typeid(B)) {}
};

struct C : public B
{
    C() : InstCounter(typeid(C)) {}
};


int main(int argc, char * argv[])
{
    std::cout << "A: " << InstCounter::getCount(typeid(A)) << std::endl;
    std::cout << "B: " << InstCounter::getCount(typeid(B)) << std::endl;
    std::cout << "C: " << InstCounter::getCount(typeid(B)) << std::endl;

    {
        A a1, a2, a3;
        B b1;
        C c1, c2;

        std::cout << "A: " << InstCounter::getCount(typeid(A)) << std::endl;
        std::cout << "A: " << a1.getCount() << std::endl;
        std::cout << "B: " << InstCounter::getCount(typeid(B)) << std::endl;
        std::cout << "B: " << b1.getCount() << std::endl;
        std::cout << "C: " << InstCounter::getCount(typeid(C)) << std::endl;
        std::cout << "C: " << c1.getCount() << std::endl;
    }

    std::cout << "A: " << InstCounter::getCount(typeid(A)) << std::endl;
    std::cout << "B: " << InstCounter::getCount(typeid(B)) << std::endl;
    std::cout << "C: " << InstCounter::getCount(typeid(C)) << std::endl;

    return 0;
}

This results in

A: 0
B: 0
C: 0
A: 3
A: 3
B: 1
B: 1
C: 2
C: 2
A: 0
B: 0
C: 0

Unfortunately you must store the type for each instance as calling typeid(*this) in InstCounter::getCount() returns the type_info for InstCounter and not the most derived type. (At least with VS2005)

NOTE: Each constructor for A, B and C have to call the InstCounter constructor explicitly then pass their typeid in. There is a down side to this, if you copy and paste this code for each new sub class you can forget to change the parameter to typeid.

Updated to add decrementing destructor.

iain
  • 10,798
  • 3
  • 37
  • 41