 #include <iostream>
#include <iostream>
 #include <memory>
#include <memory>

 using namespace std;
using namespace std;

 template<typename BeingCounted>
template<typename BeingCounted>
 class Counted
class Counted


 {
{
 public:
public:

 class TooManyObjects
    class TooManyObjects {};
{};
 static size_t getObjectsNum();
    static size_t getObjectsNum();

 protected:
protected:
 Counted();
    Counted();
 Counted(Counted&);
    Counted(Counted&);
 ~Counted();
    ~Counted();

 private:
private:
 void init();
    void init();

 private:
private:
 static size_t numObjects;
    static size_t numObjects;
 static const size_t maxObjects;
    static const size_t maxObjects;
 };
};

 template<typename BeingCounted>
template<typename BeingCounted>
 size_t Counted<BeingCounted>::numObjects = 0;
size_t Counted<BeingCounted>::numObjects = 0;

 template<typename BeingCounted>
template<typename BeingCounted>
 size_t Counted<BeingCounted>::getObjectsNum()
size_t Counted<BeingCounted>::getObjectsNum()


 {
{
 return numObjects;
    return numObjects;
 }
}

 template<typename BeingCounted>
template<typename BeingCounted>
 Counted<BeingCounted>::Counted()
Counted<BeingCounted>::Counted()


 {
{
 init();
    init();
 }
}

 template<typename BeingCounted>
template<typename BeingCounted>
 Counted<BeingCounted>::Counted(Counted&)
Counted<BeingCounted>::Counted(Counted&)


 {
{
 init();
    init();
 }
}

 template<typename BeingCounted>
template<typename BeingCounted>
 Counted<BeingCounted>::~Counted()
Counted<BeingCounted>::~Counted()


 {
{
 --numObjects;
    --numObjects;
 }
}

 template<typename BeingCounted>
template<typename BeingCounted>
 void Counted<BeingCounted>::init()
void Counted<BeingCounted>::init()


 {
{
 if( numObjects >= maxObjects )throw TooManyObjects();
    if( numObjects >= maxObjects )throw TooManyObjects();
 ++numObjects;
    ++numObjects;
 }
}

 /**////////////////////////////////////////////////
/**////////////////////////////////////////////////
 class Printer:private Counted<Printer>
class Printer:private Counted<Printer>


 {
{
 public:
public:
 using Counted<Printer>::getObjectsNum;
    using Counted<Printer>::getObjectsNum;
 using Counted<Printer>::TooManyObjects;
    using Counted<Printer>::TooManyObjects;

 public:
public:

 static Printer* make_aPrinter()
    static Printer* make_aPrinter() {return new Printer;}
{return new Printer;}

 static Printer* make_aCopy(const Printer& rhs)
    static Printer* make_aCopy(const Printer& rhs) {return new Printer(rhs);}
{return new Printer(rhs);}

 private:
private:

 Printer()
    Printer() {}
{}

 Printer(const Printer& rhs)
    Printer(const Printer& rhs) {}
{}
 };
};

 template<>
template<>
 const size_t Counted<Printer>::maxObjects = 4;
const size_t Counted<Printer>::maxObjects = 4;

 int main()
int main()


 {
{
 try
    try

 
     {
{
 auto_ptr<Printer> p1( Printer::make_aPrinter() );
        auto_ptr<Printer> p1( Printer::make_aPrinter() );
 auto_ptr<Printer> p2( Printer::make_aPrinter() );
        auto_ptr<Printer> p2( Printer::make_aPrinter() );
 auto_ptr<Printer> p3( Printer::make_aPrinter() );
        auto_ptr<Printer> p3( Printer::make_aPrinter() );
 auto_ptr<Printer> p5( Printer::make_aPrinter() );
        auto_ptr<Printer> p5( Printer::make_aPrinter() );

 cout << "current object number: "<< Printer::getObjectsNum() << endl;
        cout << "current object number: "<< Printer::getObjectsNum() << endl;

 auto_ptr<Printer> p4( Printer::make_aCopy( *p1 ) );
        auto_ptr<Printer> p4( Printer::make_aCopy( *p1 ) );
 }
    }
 catch( Counted<Printer>::TooManyObjects& exp )
    catch( Counted<Printer>::TooManyObjects& exp )

 
     {
{
 cout << "exception happened" << endl;
        cout << "exception happened" << endl;
 }
    }

 cout << "current object number: "<< Printer::getObjectsNum() << endl;
    cout << "current object number: "<< Printer::getObjectsNum() << endl;
 return 0;
    return 0;
 }
}
