0

how to answer this question?

skydoor
  • 25,218
  • 52
  • 147
  • 201

6 Answers6

6

Andrei Alexandrescu talks about this briefly in Modern C++ Design.

He outlines two disadvantages to the monostate pattern:

  1. Static functions cannot be virtual.
  2. Initialization and cleanup is not central.

Number 1 means extending or changing the class might be made more difficult. Number 2 makes it difficult to track the life-time of data.

The monostate pattern and the singleton pattern solve two different but close problems. The monostate pattern makes sure all instances of the class operate on the same data, while a singleton makes sure here is only of instance of the class to operate with.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • I don't really think they solve a different problem: in both case you have (conceptually) a single shared state. The behavior is thus the same, though the interface changes. – Matthieu M. Jan 10 '10 at 13:54
  • I am interested in the `static functions cannot be virtual`. I don't quite understand how it comes to be a problem specific to the Monostate. Reading http://c2.com/cgi/wiki?MonostatePattern it appears that many people consider the Monostate pattern to provide a classic (non-static) interface, which thus allows for virtuality and classic derivation technics while the Singleton does not allow for the use of derivation/virtuality since its constructor is private. – Matthieu M. Jan 10 '10 at 14:04
3

EDIT:

Oops, the answer no. As others have pointed out, simply setting all methods/members to static follows the Monostate pattern (of which I was not aware). I was too eager to show off my shiny Singleton template (a simplified version of Alexandrescu's SingletonHolder, really).

This answer should be downvoted.

Original Answer:

Yes. But it is less flexible than other ways of designing singletons. See Modern C++ Design by Alexandrescu and his Loki library: http://en.wikipedia.org/wiki/Loki_%28C%2B%2B%29

If you have several static singletons that depend on each other and on other global objects, you risk having problems because the order of their initialization (before main() kicks in) is tricky and can lead to unexpected results.

Using templates, you can convert normal classes into singletons. If you later decide that your singleton is no longer a singleton (i.e. you can have multiple instances), then you don't have to convert all the class's methods to non-static.

One way, using templates, is something like this:

template <class T>
class Singleton
{
public:
   static T& instance()
   {
      static T singleton;
      return singleton;
   }

private:
   Singleton() {} // Disallow construction of Singleton<T> instances
}

class Foo
{
public:
   void print() {std::cout << "Hello world\n";}
};

typedef Singleton<Foo> TheFoo;

main()
{
   TheFoo::instance().print();
}

Note that this does not prevent you from creating Foo instances, unless you make the Foo constructor private (and make Singleton a friend of Foo).

An advantage with this method over all-static classes is that you have more control over when the singleton object is constructed. It'll be constructed the first time you access the singleton. So you can have something like this:

main()
{
   TheFoo::instance(); // Make sure the Foo is constructed before the Bar
   TheBar::instance();
}

There is debate over of the appropriateness of Singletons. Some say they are global objects in disguise and can make your code less reusable. I will not comment further on that, as I have not made up my mind myself.

EDIT:

If you find TheFoo::instance() too verbose, you can always provide an inline shortcut function or use references:

inline Foo& theFoo() {return TheFoo::instance();}

main()
{
   theFoo().makeMeSomeCoffee("1 milk, 1 sugar");
   Foo& foo = theFoo();
   foo.makeMeASandwich("BLT");
}

Mmmm.... off to make coffee & sandwich.

Emile Cormier
  • 28,391
  • 15
  • 94
  • 122
  • If Foo Depends on Bar. Why not have the Foo constructor initialize it? – Martin York Jan 10 '10 at 01:00
  • Perhaps Foo knows nothing about Bar, and vice-versa. But the application wants to control the construction order for some reason unknown to Foo/Bar (order or logging messages, physical hardware considerations in embedded systems, etc.). – Emile Cormier Jan 10 '10 at 01:32
  • It does not make sense. Exposing a static only interface does not influence the order of construction / destruction... – Matthieu M. Jan 10 '10 at 13:25
  • I always thought that static objects inside a function are constructed the first time the function is called. Hmm, maybe I was wrong... gonna check on that one. – Emile Cormier Jan 10 '10 at 16:54
  • Yes, static objects in a function are constructed the first time the function is called: http://stackoverflow.com/questions/246564/what-is-the-lifetime-of-a-static-variable-in-a-c-function – Emile Cormier Jan 10 '10 at 16:57
1

This is not a particularly great idea from two standpoints.

First, if you have a pre-existing class that already has exactly what you need in a singleton, you can just declare:

MyClass singletonObject;

Then you don't need to modify it at all.

Second, it's not all that likely that your class is, in fact, exactly what you need. Concurrency issues spring to mind as a likely problem.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
1

If you represented a singleton as a static class, you would not be able to pass your singleton instance as a function argument, or store a reference to it in a variable.

Victor Nicollet
  • 24,361
  • 4
  • 58
  • 89
  • This doesn't make any sense to me at all. extern MyClass singleton; MyClass& ref = singleton; – bmargulies Jan 09 '10 at 23:51
  • The idea is actually not to have any method returning the singleton. IE all public methods of the singleton and never return any reference to the singleton. Therefore it is not possible to store it, but then it is not necessary either. – Matthieu M. Jan 10 '10 at 13:24
  • Oh, I see. That's a whole other species of singleton from what I'm familiar with. – bmargulies Jan 10 '10 at 19:21
1

My personal way to design a singleton is thus:

// header
class MySingleton
{
public:
  static int Get();
  static void Set(int i);

private:
  struct Impl;
  static Impl& Instance();
}; // class MySingleton

// source
struct MySingleton::Impl { int m_data; };

MySingleton::Impl& MySingleton::Instance()
{ 
  static Impl M_Instance;
  return M_Instance;
}

int MySingleton::Get() { return Instance().m_data; }
void MySingleton::Set(int i) { Instance().m_data = i; }

It is, in fact, reminiscent of the Pimpl idiom, adapted to static use.

Here, I can extend the interface at leisure (ie adding new methods) without breaking the binary/source compatibility (taking care about overloads), which is quite nice.

And it simplifies the client code:

// Classic
int i = MySingleton::Instance().get();

// static interface
int i = MySingleton::Get();

For the same effect, I consider it a bother to actually force the client to go through the call to Instance each and every time she wishes to call a method. Also note that by taking care myself about the initialization order fiasco, I don't force my client to bother about it, which is nice too!

Similarly, I loathe people who use this signature for Instance before making it public:

static MySingleton* Instance();

Why returning a pointer when a reference will do ? Should I expect it to be null ? If not then why using a pointer ? And it's more typing to use it too... (-> instead of .)

As a summary:

  • static interface
  • single static "state" attribute, grouping all the implementation details, and instantiated with care as to avoid the initialization order fiasco
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • You should define private or protected default and copy constructors and assignment operator to prevent creation of multiple instances as per http://en.wikipedia.org/wiki/Singleton_pattern#C.2B.2B. Use of protected allows derived singleton classes and unit test wrappers. – Clifford Jan 10 '10 at 14:28
  • I beg off: I don't need to actually do anything with the CopyConstructor or AssigmentOperator because nobody can obtain an instance of my singleton in the first place ;) For unittest / derived, the implementation could be derived from which would necessitates a `Singleton::SetInstance` method. – Matthieu M. Jan 11 '10 at 18:38
0

A bit different approach :

template <typename T>
T & getSingleton() {
    static T singleton;
    return singleton;
}

Foo & f = getSingleton<Foo>();
OneOfOne
  • 95,033
  • 20
  • 184
  • 185