6

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?

Community
  • 1
  • 1
sje397
  • 41,293
  • 8
  • 87
  • 103
  • Do you mean all instances *of the class* or a reference-counting scheme where you count *all instances that reference the same resource*? – Georg Fritzsche Jul 19 '10 at 01:47
  • I mean all instances of the class. – sje397 Jul 19 '10 at 01:49
  • Do you want a singleton? –  Jul 19 '10 at 02:05
  • No, it's just a 'normal' class. – sje397 Jul 19 '10 at 02:21
  • Just to clarify, the wording of this question is slightly different than Pietro's goal. For him, each class had its own id, while in this case you just want to count how many instances were made. – GManNickG Jul 19 '10 at 03:52
  • @GMan: Yes. I understood the first part of his question to mean what I'm asking here. I was thinking of posting the second part as another question, to keep it simple and unambiguous. That may be overkill though. – sje397 Jul 19 '10 at 04:38

2 Answers2

9

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);
Nick Strupat
  • 4,928
  • 4
  • 44
  • 56
  • +1 for the efficient solution. But this is one of the cases where i consider the virtual dtor overkill as i never expect anyone to delete through a `Countable*` - just make the dtor protected to disallow this and you are safe. – Georg Fritzsche Jul 19 '10 at 01:50
  • Wow I never considered that. Cheers! – Nick Strupat Jul 19 '10 at 01:53
  • Watch out if you're using threads. You'll need to mutex accesses to the count. And then you may run into order of initialisation issues for static instances of the Countable, as you'll need the mutex to exist before static Countable - so you'll need to look at some of the safe singleton patterns for accessing the mutex. – Michael Anderson Jul 19 '10 at 02:00
  • Question: Why's the operator > needed for a counter? – sashang Jul 19 '10 at 02:03
  • Silver, i fixed it to what i think you intended. If you don't agree feel free to roll back. – Georg Fritzsche Jul 19 '10 at 02:19
  • @Michael Anderson: Making the increment and decrement atomic operations is definitely of interest. The static initialization problems are valid but they can be avoided by simply not launching threads before `main()`. – Nick Strupat Jul 19 '10 at 02:27
  • @Georg Fritzsche: I actually didn't mean to include the identification stuff. I've removed it now. – Nick Strupat Jul 19 '10 at 02:32
  • @SilverSun: re: static init : Consider the case of a static mutex member in Countable protecting cs_count_. If two source files have static MyClass objects in them, then, depending on link order, the lock to the mutex can happen before or after the mutex constructor - leading to UB. No threads were started. There's two solutions: 1. force the construction for the mutex prior to its use, using a singleton pattern. 2. (as you suggest) is to use atomic accesses and volatile on cs_count. (Since cs_count is POD I think it is initialised at compile time not run time, avoiding the order issue) – Michael Anderson Jul 19 '10 at 03:09
8

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.

Albert
  • 65,406
  • 61
  • 242
  • 386
  • Decrementing the count in the destructor will give you the count of instances at a given point in time. If @sje397 only wants to "count the number of times the class has been instantiated", incrementing in each of the constructors should suffice. – johnsyweb Jul 19 '10 at 01:43
  • This only works if you're not creating instances of this class in multiple threads simultaneously. If you want it to be thread-safe too, you'll need to put in something like a mutex guard around the increment, and that probably means creating a mutex sometime before you start creating any of your objects and then using the mutex in your constructors. – George Jul 19 '10 at 01:43
  • For a simple counter, you can get away with using an atomic increment/decrement instruction. The details will depend on your platform. – Steven Sudit Jul 19 '10 at 01:54
  • @Steven: As long as he's not running on a multi-processor system :) @OP: If you are using GCC, here is a link for Atomic builtins: http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/Atomic-Builtins.html –  Jul 19 '10 at 02:18
  • @Changeling: By "atomic", I was referring to the version that *is* safe on a multi-processor system. Intel CPU's, for example, use a LOCK prefix. The Windows SDK included InterlockedIncrement and InterlockedDecrement functions, or you could use inline asm. Again, the details vary based on platform, so the above was just one example. – Steven Sudit Jul 19 '10 at 03:10
  • 1
    I propose a thread-safe solution using atomic operations in my answer. It requires a header from the boost libraries. – Nick Strupat Jul 19 '10 at 03:17