Markus Hütter
Markus Hütter

Reputation: 7906

Singleton Service classes in c++

Coming from a .NET/C# Background and having solid exposure to PRISM, I really like the idea of having a CompositionContainer to get just this one instance of a class whenever it is needed.

As through the ServiceLocator this instance is also globally accessible this pretty much sums up to the Singleton Pattern.

Now, my current Project is in c++, and I'm at the point of deciding how to manage plugins (external dll loading and stuff like that) for the program.

In C# I'd create a PluginService, export it as shared and channel everything through that one instance (the members would basically only amount to one list, holding the plugins and a bunch of methods). In c++ obviously I don't have a CompositionContainer or a ServiceLocator.

I could probably realize a basic version of this, but whatever I imagine involves using Singletons or Global variables for that matter. The general concern about this seems to be though: DON'T EVER DO GLOBALS AND MUCH LESS SINGLETONS.

what am I to do? (and what I'm also interested in: is Microsoft here giving us a bad example of how to code, or is this an actual case of where singletons are the right choice?)

Upvotes: 0

Views: 1697

Answers (2)

James Kanze
James Kanze

Reputation: 153909

There's absolutely nothing wrong with singletons when they're appropriate. I have my doubts concerning CompositionContainer (but I'm not sure I understand what it is actually supposed to do), but ServiceLocator is the sort of thing that will generally be a singleton in any well designed application. Having two or more ServiceLocator will result in the program not functionning as it should (because a service will be registered in one of them, and you'll be looking it up in another); enforcing this programatically is positive, at least if you favor robust programming. In addition, in C++, the singleton idiom is used to control the order of initialization; unless you make ServiceLocator a singleton, you can't use it in the constructor of any object with static lifetime.

While there is a small group of very vocal anti-singleton fanatics, within the larger C++ community, you'll find that the consensus favors singletons, in certain very restricted cases. They're easily abused (but then, so are templates, dynamic allocation and polymorphism), but they do solve one particular problem very nicely, and it would be silly to forgo them for some arbitrary dogmatic reason when they're the best solution for the problem.

Upvotes: 1

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 247919

There's really no difference between C# and C++ in terms of whether globals and singletons are "good" or "bad".

The solution you outline is equally bad (or good) in both C# and C++.

What you seem to have discovered is simply that different people have different opinions. Some C# developers like to use singletons for something like this. And some C++ programmers feel the same way.

Some C++ programmers think a singleton is a terrible idea, and... some C# programmers feel the same way. :)

Microsoft has given many bad examples of how to code. Never ever accept their sample code as "good practices" just because it says Microsoft on the box. What matters is the code, not the name behind it.

Now, my main beef with singletons is not the global aspect of them.

Like most people, I generally dislike and distrust globals, but I won't say they should never be used. There are situations where it's just more convenient to make something globally accessible. They're not common (and I think most people still overuse globals), but they exist.

But the real problem with singletons is that they enforce an unnecessary and often harmful constraint on your code: they prevent you from creating multiple instances of an object, as though you, when you write the class, know how it's going to be used better than the actual user does.

When you write a class, say, a PluginService as you mentioned in a comment, you certainly have some idea of how you plan it to be used. You probably think "an instance of it should be globally accessible (which is debatable, because many classes should not access the pluginservice, but let's assume that we do want it to be global for now). And you probably think "I can't imagine why I'd want to have two instances".

But the problem is when you take this assumption and actively prevent the creation of two instances.

What if, two months from now, you find a need for creating two PluginServices? If you'd taken the easy route when you wrote the class, and had not built unnecessary constraints into it, then you could also take the easy route now, and simply create two instances.

But if you took the difficult path of writing extra code to prevent multiple instances from being created, then you now again have to take the difficult path: now you have to go back and change your class.

Don't build limitations into your code unless you have a reason: if it makes your job easier, go ahead and do it. And if it prevents harmful misuse of the class, go ahead and do it.

But in the singleton case it does neither of those: you create extra work for yourself, in order to prevent uses that might be perfectly legitimate.

You may be interested in reading this blog post I wrote to answer the question of singletons.

But to answer the specific question of how to handle your specific situation, I would recommend one of two approaches:

  • the "purist" approach would be to create a ServiceLocator which is not global. Pass it to those who need to locate services. In my experience, you'll probably find that this is much easier than it sounds. You tend to find out that it's not actually needed in as many different places as you thought it'd be. And it gives you a motivation to decouple the code, to minimize dependencies, to ensure that only those who really have a genuine need for the ServiceLocator get access to it. That's healthy.
  • or there's the pragmatic approach: create a single global instance of the ServiceLocator. Anyone who needs it can use it, and there's never any doubt about how to find it -- it's global, after all. But don't make it a singleton. Let it be possible to create other instances. If you never need to create another instance, then simply don't do it. But this leaves the door open so that if you do end up needing another instance, you can create it.

There are many situations where you end up needing multiple instances of a class that you thought would only ever need one instance. Configuration/settings objects, loggers or wrappers around some piece of hardware are all things people often call out as "this should obviously be a singleton, it makes no sense to have multiple instances", and in each of these cases, they're wrong. There are many cases where you want multiple instances of just such classes.

But the most universally applicable scenario is simply: testing.

You want to ensure that your ServiceLocator works. So you want to test it.

If it's singleton, that's really hard to do. A good test should run in a pristine, isolated environment, unaffected by previous tests. But a singleton lives for the duration of the application, so if you have multiple tests of the ServiceLocator, they'll all run on the same "dirty" instance, so each test might affect the state seen by the next test.

Instead, the tests should each create a new, clean ServiceLocator, so they can control exactly which state it is in. And to do that, you need to be able to create instances of the class.

So don't make it a singleton. :)

Upvotes: 6

Related Questions