Sunday, December 4, 2016

Different ways to Code Singleton Pattern

Singleton Pattern

  1. Classic Singleton

#include
using namespace std;

class Single {
public:
static Single* getinstance() {
if(instance == NULL) {
instance = new Single();
cout << "object returned" << endl;
}
   return instance;
}
   void fun() {
cout << "Single class" << endl;
}
private:
static Single* instance;
static int counter;
Single() { };
Single(const Single& obj);
// need to comment it, to call getInstance() again to print address
//Single& operator=(const Single& obj);
};

Single* Single::instance = NULL;


/* we should get same address everytime */

int main()
{
   Single *obj = Single::getinstance();
   cout << "obj address=" << hex << obj << endl;
obj->fun();
cout << "obj address=" << hex << Single::getinstance() << endl;
cout << "obj address=" << hex << Single::getinstance() << endl;
Single::getinstance()->fun();
}

  1. Multiton with counter

#include
using namespace std;

class Multi {
public:
// multiton
static Multi* getinstance() {
if (counter < 2) {
instance = new Multi();
++counter;
cout << "counter:" << counter << endl;
}
return instance;
}
void fun() {
cout << "Single class" << endl;
}
private:
static Multi* instance;
static int counter;
Multi() { };
Multi(const Multi& obj);
// need to comment it, to call getInstance() again to print address
//Multi& operator=(const Multi& obj);
};

Multi* Multi::instance = NULL;
int Multi::counter = 0;

int main()
{
Multi *obj = Multi::getinstance();
obj->fun();
cout << "obj address=" << hex << obj << endl;

Multi *obj1 = Multi::getinstance();
cout << "obj1 address=" << hex << obj1 << endl;

Multi *obj2 = Multi::getinstance();
cout << "obj2 address=" << hex << &obj2 << endl;

Multi *obj3 = Multi::getinstance();
cout << "obj3 address=" << hex << &obj3 << endl;
}

It doesn’t work, go for next one
  1. Singleton (Double Checked Locking/Thread Safe)

#include
using namespace std;
#include          // std::mutex, std::lock_guard
#include      // std::logic_error
#include         // std::thread

std::mutex mtx;


class Single {
public:
static Single* getinstance() {
if(instance == NULL) {
   try {
       std::lock_guard lck (mtx);
       if(instance == NULL) {
       instance = new Single();
       cout << "object returned" << endl;
       }
   }
   catch (std::logic_error&) {
                   std::cout << "[exception caught]\n";
   }
}
   return instance;
}
   void fun() {
cout << "Single class" << endl;
}
private:
static Single* instance;
Single() { };
Single(const Single& obj);
// need to comment it, to call getInstance() again to print address
//Single& operator=(const Single& obj);
};

Single* Single::instance = NULL;


/* we should get same address everytime */

int main()
{
    std::thread threads[10];
 // spawn 10 threads:
 for (int i=0; i<10 i="" span="">
   threads[i] = std::thread(Single::getinstance);
   //*threads[i]->fun();
 }

 for (auto& th : threads) th.join();
   
   /*
   Single *obj = Single::getinstance();
   cout << "obj address=" << hex << obj << endl;
obj->fun();
cout << "obj address=" << hex << Single::getinstance() << endl;
cout << "obj address=" << hex << Single::getinstance() << endl;
Single::getinstance()->fun();
   */
}

Note: Usage in main is some what not correct, need to relook
  1. Multiton with key-value pair

#include
#include
using namespace std;

class Multi {
public:
// multiton
static Multi* getinstance(int key) {
   map::iterator it = instance.find(key);
   
   if(it != instance.end())
       return (Multi*) (it->second);
   
   instance[key] = new Multi();
   return (Multi*) instance[key];
}
void fun() {
cout << "Single class" << endl;
}

private:
static map instance;
Multi() { };
Multi(const Multi& obj);
// need to comment it, to call getInstance() again to print address
//Multi& operator=(const Multi& obj);
};

map Multi::instance; // static map initialization

//
int main()
{
Multi *obj1 = Multi::getinstance(1);
obj1->fun();
cout << "obj1 address=" << hex << obj1 << endl;
cout << "obj2 address=" << hex << Multi::getinstance(2) << endl;
cout << "obj3 address=" << hex << Multi::getinstance(1) << endl;
cout << "obj4 address=" << hex << Multi::getinstance(2) << endl;
cout << "obj5 address=" << hex << Multi::getinstance(1) << endl;
cout << "obj6 address=" << hex << Multi::getinstance(2) << endl;
}
  1. Meyers Singleton

#include
using namespace std;

class Single {
public:
// meyers singleton
static Single& getInstance() {
   static Single stat_instance;
   return stat_instance;
}
void fun() {
cout << "Single class" << endl;
}
private:
Single() { };
Single(const Single& obj);
// need to comment it, to call getInstance() again to print address
//Single& operator=(const Single& obj);
};

int main()
{
   Single& obj = Single::getInstance();
   obj.fun();
   cout << "obj address=" << hex << &obj << endl;
   obj = Single::getInstance();
   cout << "obj address=" << hex << &obj << endl;
}
  1. Singleton discovered late

#include
#include
using namespace std;

class Single {
public:
void* operator new(size_t size) {
   if (!instance) {
       instance = (Single *) malloc(size);
   }
 return instance;
}
void fun() {
cout << "Single class" << endl;
}
Single() {};
Single(const Single& obj);
Single& operator=(const Single& obj);
private:
static Single* instance;
};

Single* Single::instance = NULL;

int main()
{
   Single *obj = new Single();
   obj->fun();
   cout << "obj address=" << hex << obj << endl;
   cout << "obj address=" << hex << new Single() << endl;
   cout << "obj address=" << hex << new Single() << endl;
}
  1. Multiton discovered late

#include
#include
#include
using namespace std;

class Multi {
public:

static void* operator new(size_t size, int key) {
   map::iterator it = instance.find(key);
   if(it != instance.end())
       return (Multi*) (it->second);
   
   //instance[key] = (Multi *) malloc(size); OR
   instance[key] = (Multi *) ::operator new(size);
   return (Multi*) instance[key];
}
void fun() {
cout << "Single class" << endl;
}
Multi() { };
Multi(const Multi& obj);
Multi& operator=(const Multi& obj);
private:
static map instance;
};

map Multi::instance;


int main()
{
   Multi *obj = new (1) Multi();
   obj->fun();
   cout << "obj address=" << hex << obj << endl;
   cout << "obj address=" << hex << new (2) Multi() << endl;
   cout << "obj address=" << hex << new (1) Multi() << endl;
   cout << "obj address=" << hex << new (2) Multi() << endl;
}

Note: Once challenge which I see is everywhere we have to pass params to new operator