2

In More effective C++ Meyers has described a way to count the instantiation of the objects using an object counting base class (item 26). Is it possible to implement the same using composition technique as below . Is there a specific advantage using private inheritance and what are the drawbacks of using composition in this case.

ps:- I have reused the code from More effective C++ with small modification.

    #ifndef COUNTERTEMPLATE_HPP_
    #define COUNTERTEMPLATE_HPP_
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>

    template <class BeingCounted>
    class Counted {
    public:
        static int ObjectCount(){return numOfObjects;}
        Counted();
        Counted(const Counted& rhs);
        ~Counted(){--numOfObjects;}
    protected:
    private:
        static int numOfObjects;
        static int maxNumOfObjects;
        void init();
    };

    template<class BeingCounted> Counted<BeingCounted>::Counted()
    {
        init();
    }

    template<class BeingCounted> Counted<BeingCounted>::Counted(const Counted& rhs)
    {
        init();
    }

    template<class BeingCounted> void Counted<BeingCounted>::init()
    {
        if(numOfObjects>maxNumOfObjects){}
        ++numOfObjects;
    }

    class Printer
    {
            public:
        static Printer* makePrinter(){return new Printer;};
        static Printer* makePrinter(const Printer& rhs);
        Counted<Printer>& getCounterObject(){return counterObject;}
        ~Printer();
            private:
        Printer(){};
        Counted<Printer> counterObject;
        Printer(const Printer& rhs){};
    };

    #endif /* COUNTERTEMPLATE_HPP_ */

David G
  • 94,763
  • 41
  • 167
  • 253
uknowit
  • 33
  • 5
  • Private inheritance can make use of the empty base class optimization. [Live example](http://coliru.stacked-crooked.com/a/c68bae310c173e60) – dyp May 31 '14 at 13:07
  • Looks like your `init` implementation is invalid for the beyond maximum case – SomeWittyUsername May 31 '14 at 13:18
  • @icepack Yes.Actually it should throw exception. I have not added exception because my question doesn't depend on that. – uknowit May 31 '14 at 17:28

2 Answers2

2

This question is related to

Of those two, one is probably a duplicate of the other. But neither answers this question, and I'm somehow reluctant to post my answer to one of them.


Private inheritance can make use of the empty base class optimization:

class Printer0
{
    Counted<Printer0> counterObject;
    int m;
};

class Printer1 : Counter<Printer1>
{
    int m;
};

Clang++ and g++ both say sizeof(Printer0) == 8 and sizeof(Printer1) == 4.

The reason is that data members have to have different addresses, but a single empty base class does not need to use up memory in the object. So counterObject is one byte large, and int is aligned to 4 byte, therefore Printer0 looks like this:

  | | X X |       | 
  0 1 2 3 4 5 6 7 8 9
          ^~~~~~~~~ m
      ^~~~ padding
  ^~~~ counterObject
Community
  • 1
  • 1
dyp
  • 38,334
  • 13
  • 112
  • 177
0

Composition forces you to "pollute" the code of your class with the meta-data (i.e. counter object) that isn't related to its main business, in my opinion making the code less readable for this case. Also see @dyp answer regarding the technical aspect of empty class optimization.

SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85