hg_git
hg_git

Reputation: 3084

using namespaces instead of singletons

Recently I posted a question on SO regarding usage of a class which carried a bit of separate functionality that it should've, ideally. I was recommended to learn about singleton pattern so that only one instance is created of the class and it manages the set of operations revolving around the data it encapsulates. You can see the question here - using Static Container for base and derived classes .


Now consider this code -

#include <iostream>
#include <string>
#include <unordered_map>

class A{
    std::string id;
  public:
    A(std::string _i): id(_i){}
    virtual void doSomething(){std::cout << "DoSomethingBase\n";}
};

class B : public A{
    std::string name;
  public:
    B(std::string _n):name(_n), A(_n){}
    void doSomething(){std::cout << "DoSomethingDerived\n";}
};

namespace ListA{
    namespace{
        std::unordered_map<std::string, A*> list;   
    }
    void init(){
        list.clear();
    }
    void place(std::string _n, A* a){
        list[_n] = a;
    }
}


int main() {
    ListA::init();
    ListA::place("b1", new B("b1"));
    ListA::place("a1", new A("a1"));
    return 0;
}

Ignoring the fact that I'm still using raw pointers which are leaking memory if program doesn't terminates as it is, is this a good alternative to using global static variables, or a singleton?


With regard to previous question, I've reorganized class A(base class) and class B(derived classes) independent of a namespace that manages a list of these objects. So is this a good idea, or a totally bad practice? Are there any shortcomings for it?

A good singleton implementation I was suggested was as follows -

class EmployeeManager
{
    public:
        static EmployeeManager& getInstance()
        {
            static EmployeeManager    instance; // Guaranteed to be destroyed.
                                  // Instantiated on first use.
            return instance;
        }
    private:
        EmployeeManager() {};
        std::unordered_map<std::string, Employee&> list;
    public:
        EmployeeManager(EmployeeManager const&) = delete;
        void operator=(const&) = delete;
        void place(const std::string &id, Employee &emp){
            list[id] = emp;
        }
};

class Employee
{
    public:
        virtual void doSomething() = 0;
};

class Writer : public Employee
{
    private: 
        std::string name_;
    public:
        Writer(std::string name) : name_(name) {};
        void doSomething() { };
};

Honestly I've never tried singleton pattern and I'm shying away to use it directly since I've no prior experience and I would rather first use it in my pet projects.

Upvotes: 4

Views: 2212

Answers (3)

Ethouris
Ethouris

Reputation: 1901

I'm not sure if you know that already, but you need to remember that Singleton really is a global variable with lazy initialization.

Lazy initialization is a tool to fix a problem of having the object initialized always at the time when you really want to use it - be it for some real-program function, or initializing another, dependent object. This is done to delay initialization until the first moment when you use the object.

The static object is simply initialized at the moment when it first appears to need to be created - however when this moment really is, is undefined, at least in C++.

You can replace lazy initialization with the static initialization, but you must ensure somehow that the initialization happens in defined order.

Defining variables inside the namespace is nothing else than declaring the variables globally. Namespaces are open, rules inside the namespace are the same as outside the namespace, except the symbol resolution.

What you can do to enforce ordered initialization is to create one global variable with all dependent global objects inside, in the form of struct that will contain all them as fields (not static fields!). Note though that the exact order of initialization will be only ensured between objects being fields of that structure, not between them and any other global objects.

Upvotes: 1

Florian Salihovic
Florian Salihovic

Reputation: 3961

Your question can be answered without any line of code, as it was answered by a lot of people in the past. Singletons are bad because your code will depend on one class and its implementation. What you want though is to have independent units which don't know about the implementations of the interfaces they talk to. Propagation of values / reference should (in fact it must be done for large maintainable systems) via reference passing from containing object to its child, an observer / event system or an event / message bus. Many frameworks use at leat two of these approaches ... I highly recommend sticking to best practices.

Upvotes: 0

marcinj
marcinj

Reputation: 50036

is this a good alternative to using global static variables, or a singleton?

no, because you might encounter another problem: static initialization order fiasco. There are ways to fix it - but with functions with static variables - which looks just like singletons.

... but why do you need a global variables (even in namespaces) or singletons? In you first example, it would be perfectly fine if instead of namespace ListA you had struct ListA - plus remove that namespace{. Then you have:

int main() {
    ListA list;
    list.init();
    list.place("b1", new B("b1"));
    list.place("a1", new A("a1"));
}

and it looks fine.

Then your singleton aproach, once again - no need for it - create variable of type EmployeeManager in your main function, if you need to use it in some other class, then pass it by reference or pointer.

Upvotes: 3

Related Questions