16

Just the other day I have seen code that uses the so called singleton pattern. Meaning something along the lines of

class MySingleton{
public:
    void foo() { ... }
    static MySingleton&get_instance(){
        static MySingleton singleton;
        return singleton
    }
private:
    MySingleton(){ ... }
    ~MySingleton(){ ... }
    int bar;
};

I do see why one would want to do that:

  • Make the instance globally accessible.
  • Make sure that there is never more than one instance of that class.

However I do not see why this way of doing things is superior to a couple of free functions. The way I'd implement it is to put

namespace some_name{
    void foo();
}

in the header and

namespace some_name{
    void foo(){
        ...
    }
}

in the implementation file. If I need initialization and/or cleanup I either add a couple of functions that must be explicitly called or I add

namespace{
    class Dummy{
        Dummy(){ ... }
        ~Dummy(){ ... }
    }dummy;
}

into the implementation file.

I know that this is from a semantic point of view a singleton, however I see the first variant used far more often in C++ Code than the second. Why? I consider the second version to be slightly superior, so I asking myself if I'm missing something obvious.

  • The second version is simpler to implement and less error prone. In the first variant the private copy constructor is missing on purpose to demonstrate this. In the second variant there is no way to do this error.
  • Implementation and interface are better separated in the second version. In the first all private members must be declared in the header. This has the advantage that you can rewrite the implementation from scratch and don't even need to recompile anything that uses the singleton. When using the first variant it is very likely that you have to recompile all user code even when only changing slight implementation details.
  • Implementation details are hidden in both cases. In the first variant using private and in the second variant using unnamed namespaces.

Can you please explain me why everybody uses the first variant? I don't see a single advantage over the good old way of doing things in C.

B.S.
  • 1,435
  • 2
  • 12
  • 18
  • You don't need a copy constructor in the singleton pattern. The whole purpose of the singleton pattern is to make sure that one and only one instance of the class can be created. – erelender Sep 08 '09 at 13:52
  • 4
    When discussing singletons, it is necessary to add that singletons are a *bad* design pattern and should be avoided for reasons stated here: http://stackoverflow.com/questions/1392315/problems-with-singleton-pattern – Gavin Miller Sep 08 '09 at 13:58
  • 2
    Yes you do need a private copy constructor! Otherwise you get a default public one an can write
    MySingleton foo(MySingleton::get_instance());
    and have a second instance.
    – B.S. Sep 08 '09 at 14:12
  • Both are hard to write tests for as you can't control object creation. – jameszhao00 Sep 08 '09 at 14:56
  • @erelender the keyword there is "private" – moswald Sep 08 '09 at 15:12
  • @LFST: Singelton is only bad if abused (unfortunately nobody knwos how to use it correctly so it is always abused). – Martin York Sep 08 '09 at 18:10
  • One difference I see over using a global is the singelton is guranteed to be lazily evaluated (which could be important for expensive initialization). Two:I dont see any gurantees in your code about only creatng one instnace. – Martin York Sep 08 '09 at 18:12
  • @james: Writting tests is hard only if you follow the pattern above blindely. With a little re-work the pattern above can be modified to use a factory to instanciate the singelton thus makeing it easy to test. – Martin York Sep 08 '09 at 18:14
  • 1
    Just make it a global static and thumb your nose at everybody. – slashmais Sep 08 '09 at 19:31

6 Answers6

7

According to the party line (E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, Reading, MA, 1995, p. 128), the singleton offers the following advantages over the solution you propose.

  • You can refine the operations and the representation e.g. through subclassing.
  • You can change your mind at a later point and have multiple instances.
  • You can override the singleton's methods polymorphically.
  • You can configure your application at runtime by initializing the singleton instance with the class you need.

Having said that, in most cases I consider the additional complexity excessive and rarely use the pattern in the code I write. But I can see its value when you design an API that others will use.

Diomidis Spinellis
  • 18,734
  • 5
  • 61
  • 83
  • "You can change your mind at a later point and have multiple instances." In practice this isn't true because it, er, encourages coupled code. – Dustin Getz Sep 08 '09 at 15:17
  • 1
    @Dustin Getz How does it encourage coupled code any more than anything else? – Imagist Sep 08 '09 at 15:23
  • All of these can be accomplished by free functions and using function pointers internally to change the implementation. The only difference is the interface. ie do you like typing instance() or not. – Greg Rogers Sep 08 '09 at 16:42
  • 1
    True, you can do OO programming with structures containing function pointers. The Unix kernels do it for implementing VFS. But language-supported OO is a lot nicer. – Diomidis Spinellis Sep 09 '09 at 13:32
4

does this help?

What is so bad about singletons? http://steve.yegge.googlepages.com/singleton-considered-stupid

Rephrased: A singleton is a glorified global, so just 'implement' it as a global.

Community
  • 1
  • 1
Dustin Getz
  • 21,282
  • 15
  • 82
  • 131
  • 1
    Suppose the singleton opens a config file or a logging stream, id you remember to call the global setup function before your first use of the log or config? – Martin Beckett Sep 08 '09 at 14:01
  • @MGB its still a class with ctors and stuff – Dustin Getz Sep 08 '09 at 15:14
  • Not really. It misses the point of my question. I'm refering to the way to implement a singleton in C++. Not to the question if one should use one in the first place. – B.S. Sep 08 '09 at 16:07
  • Its also lazily initialized (*unlike a global). So if it is empensize you dont incur the initialization cost if you dont use it. – Martin York Sep 08 '09 at 18:09
3

The construction of static MySingleton singleton; gets called on the first use. (When get_instance() is called.) If it is never called it never calls the constructor. Your method will call the constructor at static construction time. The previous method allows for the order and timing of the constructors being called. You method will order the construction of each singleton according to the compiler static initialisation order.

Charles Beattie
  • 5,739
  • 1
  • 29
  • 32
  • It is implementation defined when the constructor of local static variables are run. Using the second variant you have reliable behavior. Also you can add a flag and get the lazy behavior in a portable way. – B.S. Sep 08 '09 at 14:18
  • 2
    It is implementation defined when the constructor of local static variables are run. -> Not true when they are in a function or an if statment etc... The memory can get allocated at anytime before main() but the constructor of these types of statics is called when the program pointer passes it for the first time. When they're defined outside a function of some sort then when the constructor gets called is implementation specific. – Charles Beattie Sep 08 '09 at 15:00
  • @Ben. The order of evaluation of staic function variables is well defined. It is at the point of first use. Thus giving you the equivalent of the flagged you suggest but done by the compiler (thus less chance of an error (not saying compielr is perfect but usually better than a human)) (also on gcc it is thread safe, and hopefully thread safe be standard in the next version of C++). – Martin York Sep 08 '09 at 18:19
1

To have functions + static data emulate the singleton pattern would rely on C++'s file scoping and separate-compilation. These are compiler constructs rather than language constructs. The singleton class pattern allows data encapsulation regardless of location with respect to compilation-units; it is correctly encapsulated even if it is defined in a file with other classes and functions.

Also it would not in fact emulate the behaviour of the singleton pattern, but merely that of a static object, which is not the same thing. A singleton's lifetime is independent of the life of the process that contains it. The correctly formed singleton is instantiated on first use, whereas static data is instantiated and initialised before main() is started. This may be a problem, if say construction of the object relies on the existence of some other run-time entity. Also the singleton object occupies no memory (other than its static instance pointer) until it is instantiated. It may also be destroyed and re-created at any time, and indeed many times.

Note if you modify your singleton to make the constructor protected rather than private, you can subclass it (and thus easily apply reuse singleton pattern), you can't do that with a static object, or an object with all static members, or functions with file scoped static data, or any other way you may try to get around doing it correctly.

There is nothing wrong with your suggestion per se, just so long as you are aware that it is not a singleton pattern, and lacks it's flexibility.

Clifford
  • 88,407
  • 13
  • 85
  • 165
0

The problem with just using free functions is that those don't by default get shared persistent behavior, like your singleton class can get with member variables and constants.

You could proceed to use static global variables to do the same thing, but for someone trying to figure that out, that makes the scope of what they have to look at to understand those routines' behavior nearly unlimited. With a singleton class, everything is nicely organized into one class for the reader to examine.

T.E.D.
  • 44,016
  • 10
  • 73
  • 134
  • I don't see why it is harder to learn how to use non error prone static global variables, than learning how to do the error prone voodoo stuff necessary to ensure that there exists only one instance. Newbies normally use global variables far too often. This shows that the concept of global data is pretty intuitive. – B.S. Sep 08 '09 at 14:21
0

Personally, I use singletons when I want to have control of when the constructor is executed for the first time.

For example; if I have a singleton for my log-system, the code to open a file for writing is put into the singleton constructur, which is is called like; Logger.instance(); in my startup process. If i'd use a namespace I would have that control.

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90