I would like to be able to instantiate a particular (and otherwise normal) class (the source of which I can modify) and count the number of times the class has been instantiated (e.g. like this). But I would like to include all instances in my total count, even some which are created via the copy constructor in standard containers.
Would it be appropriate to have all the constructors (including the copy constructor) of my class increment a static counter? If so, is it possible to ensure my class still conforms to the requirements of standard containers (i.e., T(x) is equivalent to x), by overriding other operators for example?
A common way of accomplishing this is with a class template from which you inherit.
template <typename T>
class Countable
{
static unsigned cs_count_;
public:
Countable() { ++cs_count_; }
Countable( Countable const& ) { ++cs_count_; }
virtual ~Countable() { --cs_count_; }
static unsigned count() { return cs_count_; }
};
template <typename T>
unsigned Countable<T>::cs_count_ = 0;
So to use this I would write:
class MyClass : public Countable<MyClass> { };
Below is a thread-safe version. It uses a class from boost to ensure the increment, decrement, and read operations are atomic on the supported platforms.
#include <boost/detail/atomic_count.hpp>
template <typename T>
class Countable
{
static boost::detail::atomic_count cs_count_;
protected:
~Countable() { --cs_count_; }
public:
Countable() { ++cs_count_; }
Countable( Countable const& ) { ++cs_count_; }
static unsigned count() { return cs_count_; }
};
template <typename T>
boost::detail::atomic_count Countable<T>::cs_count_(0);
Think of the static class variable as a global variable which is just in the namespace of the class. Incrementing or doing other things with it will not have any side effects on other code, i.e. your constructors and other operators will behave exactly as before.
I.e., you are right: Just increment in all constructors and decrement in the destructor.
Of course, as George pointed out, if you want to have it multithreading safe, you need to add some multithreading safe code around the access to your counter variable (for example some mutex). Or as Steven pointed out, you might also use atomic increment/decrement instructions (but the usage will depend on the platform). Those would be a lot faster. Though, you have to be careful because in some cases that wont work in multi-processor environments. You can use Boost's atomic_count
to be on the safe side.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With