Counting Objects in C

Counting Objects in C++

Every object of a class must be constructed using one of the constructors, so it is a simple idea to have some kind of a counter that is incremented by the constructors every time they construct a new object of the class. Similarly, the destructor can decrement the counter every time it destroys an object. At termination of the program we can display a count of the remaining objects to determine if they leak or not.

The idea is simple, but its realization is more complex. Providing such a counter for a single class - and modifying all its constructors and the destructor to work with the counter - is not too complicated. But we do not want to do this for each class separately, so we need an approach that is a bit more sophisticated. (Of course, as before, we would like to be able to turn the counting on or off in a simple way that entails minimal overhead during the program's execution when it is turned off.) There are basically two approaches that feature a special class OBCOUNT , which takes care of the counting business. In the first approach, an OBCOUNT object is embedded in the definition of every class; in the second approach, each class to be part of the counting process is derived from class OBCOUNT . The former technique is a bit easier to understand, but its implementation requires more memory during execution and it is a bit awkward to turn on and off, so I have decided to discuss the latter approach here.

We want the class OBCOUNT to be usable with any class in our program, so we parameterize it with a template class X . This will allow us to make OBCOUNT class-specific for any class.

 #ifdef _COUNT_ON   class X; //just for the compiler so it can deal with the template   template <class X> class OBCOUNT   {   public:     OBCOUNT() { count++; }     OBCOUNT(const OBCOUNT& c) { count++; }     ~OBCOUNT() { count--; }   protected:     static size_t count;   };//end class OBCOUNT #endif //_COUNT_ON 

We then modify every class definition of a class that we are interested in counting as follows :

 #ifdef _COUNT_ON  class ACLASS : private OBCOUNT<ACLASS> #else  class ACLASS #endif { public:   ACLASS() { ... }   ...  //all other constructors  ~  ACLASS() { ... }   #ifdef _COUNT_ON     static void ReportCount() {       cout << "ACLASS::count=" << count << '\n' << flush;     }   #endif   ...   ... };//end class ACLASS #ifdef _COUNT_ON  size_t OBCOUNT<ACLASS>::count=0;  // define and init ACLASS counter #endif 

You can see the coding is straightforward, and if the counting is turned off ( _COUNT_ON is not defined) then the class ACLASS has no overhead due to counting. There are two comments to be made, though. First, the reader may ask why the class ACLASS is derived from the class OBCOUNT as private. The reason is rather simple: we want to prevent having anywhere in our program a statement like delete p where OBCOUNT *p . By deriving ACLASS from OBCOUNT as private, the compiler will not allow such a statement. Had we not done so, we would have to provide a virtual destructor for OBCOUNT and thus greatly complicate our program. However, since OBCOUNT is there only for debugging purposes when the count is turned on, such statements should not be in our program anyway, so this restriction is a price we gladly pay. The second comment concerns the actual definition of the counter for the class ACLASS . Here we placed it right after the class definition, but if the class definition is in a header file included in many source files of our program, the compiler would complain. It has to be simply defined only once in the body of the program.

It is clear from our discussion that tracing memory leaks in C++ programs is not an easy task, primarily because memory allocation and deal-location is handled by operators that are a part of the language and are not outside entities like the standard allocators in C. The question of whether this could be designed differently is still being discussed within the C++ community. There is no simple answer, since unwinding the system stack after exceptions requires the compiler to know about the allocations and deallocation during construction of an object. The finer points of this discussion are not part of this book's focus, but I encourage the interested reader to get involved in the debate. On the other hand, C++ provides some powerful techniques that can be employed to detect or prevent memory leaks, as our example of object counting illustrates. There is one more topic that fits in this chapter and has a reasonable solution in C++: the problem of undetermined ownership.



Memory as a Programming Concept in C and C++
Memory as a Programming Concept in C and C++
ISBN: 0521520436
EAN: 2147483647
Year: 2003
Pages: 64

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net