Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass argument in a singleton

I've been wondering how to pass argument to a singleton contructor. I already know how to do a singleton, but I've been unlucky to find a way to do it.

Here is my code (part of it).

Questionnary* Questionnary::getInstance(){

    static Questionnary *questionnary = NULL;

    if(questionnary == NULL){
        cout << "Object created";
        questionnary = new Questionnary();

    }
    else if(questionnary != NULL){
        cout << "Object exist";
    }

    return questionnary;
}

Questionnary::Questionnary(){
    cout << "I am an object";
}

//This is want i want to acheive
Questionnary::Questionnary(string name){
    cout << "My name is << name;
}

Many thanks in advance

(BTW i know how and why a singleton is bad)

like image 896
Chax Avatar asked Jan 28 '14 01:01

Chax


People also ask

Can singleton class have parameters?

Can singleton class have parameters? The parametric singleton pattern allows for one instance of a class for a given set of parameters. It provides a single point of global access to a class, just the way the singleton pattern does [Cooper]. The difference is that, for each new parameter, another instance is created.

Can Singleton constructor have parameters?

However, singleton is a principle in Java that can only be created when: A private class has a default constructor. Any protected static class type object is declared with the null value. A parameter is assigned to the constructor of the singleton class type (as we did in step two).

Why you should not use singletons?

The most important drawback of the singleton pattern is sacrificing transparency for convenience. Consider the earlier example. Over time, you lose track of the objects that access the user object and, more importantly, the objects that modify its properties.

How do you handle a class Singleton?

We can distinguish a Singleton class from the usual classes with respect to the process of instantiating the object of the class. To instantiate a normal class, we use a java constructor. On the other hand, to instantiate a singleton class, we use the getInstance() method.


2 Answers

You don't need to allocate the instance of singleton dynamically. It could look the following way (this is sometimes called "lazy loading singleton" ~ the instance is created late & kinda "automatically"):

#include <iostream>
#include <string>

class Questionnary
{
private:
    // constructor taking string:
    Questionnary(const std::string& name) : name_(name) { }
public:
    static Questionnary& getInstance(const std::string& name)
    {
        static Questionnary q(name);
        std::cout << "My name is: " << q.name_ << std::endl;
        return q;
    }
private:
    std::string name_;
};

int main() {
    Questionnary::getInstance("Josh");
    Questionnary::getInstance("Harry");
}

output:

My name is: Josh
My name is: Josh

Note that constructor will be called only once right when the getInstance is called for the first time.

like image 103
LihO Avatar answered Oct 14 '22 06:10

LihO


Let me extend Martin York's answer for your use case. I recommend using pointer for argument(s) in this particular situation, as we make use of its inherent property, that it can be "empty".

class Questionnary
{
  std::string _str;

  static Questionnary& getInstanceImpl(std::string* const s = nullptr)
  {
    static Questionnary instance{ s };
    return instance;
  }

  Questionnary(std::string* const s)
    : _str{ s ? move(*s) : std::string{} } // employ move ctor
  {
    if (nullptr == s)
      throw std::runtime_error{ "Questionnary not initialized" };
  }

public:
  static Questionnary& getInstance()
  {
    return getInstanceImpl();
  }
  static void init(std::string s) // enable moving in
  {
    getInstanceImpl(&s);
  }

  Questionnary(Questionnary const&) = delete;
  void operator=(Questionnary const&) = delete;
};

I find this approach less confusing, as it let's you get the instance after first initialization without (anyway discarded) arguments:

// first init
Questionnary::init("my single Questionnary");

// later on ...
Questionnary& q = Questionnary::getInstance();

Edit: Removed argument from getInstance function and a few optimizations.

like image 34
neonxc Avatar answered Oct 14 '22 07:10

neonxc