How to pass an argument to singleton

I was wondering how to pass an argument to a one-contact constructor. I already know how to make a singleton, but I was not lucky to find a way to do this.

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;
}

Thank you very much in advance

(By the way, I know how and why singleton is bad)

+5
source share
5 answers

You do not need to allocate a singleton instance dynamically. It may look like this (sometimes called a “lazy loading singleton" ~ the instance is created late and "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");
}

exit:

My name is: Josh
My name is: Josh

, , getInstance .

+4

. () , , "".

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;
};

, ( , ) :

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

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

: getInstance .

+3

, getInstance(), CreateInstance . :

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

    static Questionnary* m_instance;
public:
    static void createInstance(const std::string& name)
    {
        assert(!m_instance);
        m_instance = new Questionary(name);
    }

    static void destroyInstance()
    {
        assert(m_instance);
        delete m_instance;
    }

    static Questionnary* Questionnary::getInstance()
    {
        assert(m_instance);
        return m_instance;
    }
private:
    std::string name_;
};
+1

, Modern C++, :

#ifndef SINGLETON_H
#define SINGLETON_H

template <typename C, typename ...Args>
class singleton
{
private:
  singleton() = default;
  static C* m_instance;

public:
  ~singleton()
  {
    delete m_instance;
    m_instance = nullptr;
  }
  static C& instance(Args...args)
  {
    if (m_instance == nullptr)
      m_instance = new C(args...);
    return *m_instance;
  }
};

template <typename C, typename ...Args>
C* singleton<C, Args...>::m_instance = nullptr;

#endif // SINGLETON_H

:

  int &i = singleton<int, int>::instance(1);
  UTEST_CHECK(i == 1);

  tester1& t1 = singleton<tester1, int>::instance(1);
  UTEST_CHECK(t1.result() == 1);

  tester2& t2 = singleton<tester2, int, int>::instance(1, 2);
  UTEST_CHECK(t2.result() == 3);

The problem is that instance () requires arguments on every call, but uses them only on the first call (as noted above). The default arguments cannot be used at all. It might be better to use the create (Args ...) method, which should precede the call to instance () or throw an exception.

+1
source
//! @file singleton.h
//!
//! @brief Variadic template to make a singleton out of an ordinary type.
//!
//! This template makes a singleton out of a type without a default
//! constructor.

#ifndef SINGLETON_H
#define SINGLETON_H

#include <stdexcept>

template <typename C, typename ...Args>
class singleton
{
private:
  singleton() = default;
  static C* m_instance;

public:
  singleton(const singleton&) = delete;
  singleton& operator=(const singleton&) = delete;
  singleton(singleton&&) = delete;
  singleton& operator=(singleton&&) = delete;

  ~singleton()
  {
    delete m_instance;
    m_instance = nullptr;
  }

  static C& create(Args...args)
  {
    if (m_instance != nullptr)
      {
    delete m_instance;
    m_instance = nullptr;
      }
    m_instance = new C(args...);
    return *m_instance;
  }

  static C& instance()
  {
    if (m_instance == nullptr)
      throw std::logic_error(
        "singleton<>::create(...) must precede singleton<>::instance()");
    return *m_instance;
  }
};

template <typename C, typename ...Args>
C* singleton<C, Args...>::m_instance = nullptr;

#endif // SINGLETON_H

as well as:

void
singleton_utest::test()
{
  try
    {
      singleton<int, int>::instance();
      UTEST_CHECK(false);
    }
  catch (std::logic_error& e)
    {
      UTEST_CHECK(true);
    }

  try
    {
      UTEST_CHECK((singleton<int, int>::create(1) == 1));
      UTEST_CHECK((singleton<int, int>::instance() == 1));
    }
  catch (...)
    {
      UTEST_CHECK(false);      
    }

  using stester0 = singleton<tester0>;

  try
    {
      stester0::instance();
      UTEST_CHECK(false);
    }
  catch (std::logic_error& e)
    {
      UTEST_CHECK(true);
    }

  try
    {
      UTEST_CHECK((stester0::create().result() == 0));
      UTEST_CHECK((stester0::instance().result() == 0));
    }
  catch (...)
    {
      UTEST_CHECK(false);      
    }

  using stester1 = singleton<tester1, int>;

  try
    {
      stester1::instance();
      UTEST_CHECK(false);
    }
  catch (std::logic_error& e)
    {
      UTEST_CHECK(true);
    }

  try
    {
      UTEST_CHECK((stester1::create(1).result() == 1));
      UTEST_CHECK((stester1::instance().result() == 1));
    }
  catch (...)
    {
      UTEST_CHECK(false);      
    }

  using stester2 = singleton<tester2, int, int>;

  try
    {
      stester2::instance();
      UTEST_CHECK(false);
    }
  catch (std::logic_error& e)
    {
      UTEST_CHECK(true);
    }

  try
    {
      UTEST_CHECK((stester2::create(1, 2).result() == 3));
      UTEST_CHECK((stester2::instance().result() == 3));
    }
  catch (...)
    {
      UTEST_CHECK(false);      
    }
}
0
source

Source: https://habr.com/ru/post/1523989/


All Articles