#include <iostream>

using namespace std;

struct AbstractResource {
  int ref_count;
  virtual void do_something() = 0;
  AbstractResource() : ref_count(0) {}
  virtual ~AbstractResource(){}
};

struct Resource0 : public AbstractResource {
  void do_something(){
    cout << "Do somthing with Resource0 at " << this << endl;
  }
  Resource0() : AbstractResource() {
    cout << "Created : Resource0 at " << this << endl;
  }
  ~Resource0(){
    cout << "Clean-uped : Resource0 at " << this << endl;
  }
};

struct Resource1 : public AbstractResource {
  void do_something(){
    cout << "Do somthing with Resource1 at " << this << endl;
  }
  Resource1() : AbstractResource() {
    cout << "Created : Resource1 at " << this << endl;
  }
  ~Resource1(){
    cout << "Clean-uped : Resource1 at " << this << endl;
  }
};

struct Resource {
  AbstractResource *delegatee;
  void do_something() {
    delegatee->do_something();
  }
  Resource(AbstractResource *resource) 
      : delegatee(resource) {
    (delegatee->ref_count)++;
  }
  Resource(const Resource &orig)
      : delegatee(orig.delegatee) {
    (delegatee->ref_count)++;
  }
  Resource &operator=(const Resource &rhs){
    if(delegatee != rhs.delegatee){
      if(--(delegatee->ref_count) <= 0){
        delete delegatee;
      }
      delegatee = rhs.delegatee;
      (delegatee->ref_count)++;
    }
    return *this;
  }
  ~Resource() {
    if(--(delegatee->ref_count) < 1){
      delete delegatee;
    }
  }
};

struct ResourceManager {
  static Resource get_resource(const int &type){
    return Resource((type != 0) 
        ? (AbstractResource *)new Resource1() 
        : (AbstractResource *)new Resource0()); 
  }
};

int main() {
  Resource r0(ResourceManager::get_resource(0));
  r0.do_something();
  
  Resource r1(ResourceManager::get_resource(1));
  r1.do_something();
  
  {
    Resource r0_copy(r0);
    r0_copy.do_something();
    
    Resource r1_another(ResourceManager::get_resource(1));
    r1_another.do_something();
  }
  
  return 0;
}
