Sign in to follow this  

Singleton Pattern, C++

This topic is 3837 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I have a problem. I read about singleton design pattern and got the idea, but lets say I want to develop a CLog class. Class that will log everything I need and put in a file. I want to do this class Singleton. This class will have, hmm lets say a static method: statics CLog* Instance(const char* filename); When this method called file with given filename will be created(if needed) and opened. Next there will be some methods like write to file and etc. Now at the end when program exit I need to close this file, free some allocated memory (if was allocated). But the only way to do it as I see is by created a new method like Exit(); that will do all this. The problem is this method need to be called bu user and its not behaving like class destructor. Is there any option to created some function that will be called automatically when Singleton will be destroyed? Or maybe if constructor and destructor declared as private/protected they will be called any way when object created/destroyed? Thanks.

Share this post


Link to post
Share on other sites
I wish I was at my computer, so that I could show you my logFile class. Basically my class was a non-singleton, that you didn't have to pass references too. It also formatted output like this:

00:12:82 [PHYSICS]: Loading physics engine.
00:12:82 [PHYSICS]: Initializing physics engine.
00:12:82 [PHYSICS]: Physics engine initialized.
>00:12:82 [PHYSICS]: <ERROR> Couldn't execute collision.

To display it would be something like this;

log_file lf("log1.log", "physics");

lf << "Loading physics engine.";
lf << "Initializing physics engine.";
lf << "Physics engine initialized.";
lf.error("Couldn't execute collision.");


All you have to do is #include "log_file.hpp", and you could use the code like that. The benefit (one of many) of the non-singleton, was the fact that you could log to many different files, like this:

log_file lf1("logger1.txt");
log_file lf2("logger2.txt");

lf1 << "Yeah!";
lf2 << "Yeah!";

And everything would work fine.

Also, it's not global, so you don't have to worry about thing getting into the global namespace, which is nice.

I'd think of a way to design something similar to that above, as it works great for me.

Share this post


Link to post
Share on other sites
Ok I got your idea but lets discuss another class: CApplication class.
Formally I (or user whatever =\ ) can create only one application so there I need to use singleton (or maybe there is another way something like shared_ptr as you said before [Didn't checked it yet]).

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Quote:
Original post by s.kwee
Formally I (or user whatever =\ ) can create only one application

Why?

Because logically there can be only one application.
Even if not I want to limit number of applications to one, I'm designing software and thats how I want it to behave.

Share this post


Link to post
Share on other sites
Quote:
Original post by s.kwee
Quote:
Original post by Sneftel
Quote:
Original post by s.kwee
Formally I (or user whatever =\ ) can create only one application

Why?

Because logically there can be only one application.
Even if not I want to limit number of applications to one, I'm designing software and thats how I want it to behave.


Don't create more than one. Have you ever "accidentally" created an instance of something when you didn't plan to? It is pretty hard to in C++, given that you have to declare variables.

It would take *extra work* for you to impose such a limit on your program. That extra work could contain bugs. Would your extra code handle tearing down and creating a new Application object without terminating the process?

I have several objects in my game which only have one instance at a time. But there isn't any code guarding that. I could create 2 renderers, 2 world objects etc.

What does the Application object do anyway? What are its responsibilities?

Share this post


Link to post
Share on other sites
Quote:
Original post by s.kwee
Because logically there can be only one application.

Then create only one. The singleton should only be used where it would literally be logically impossible to create more than one. Hint: There are extremely few situations where singletons are appropriate. If you aren't developing for an embedded platform, it's likely that in your application there are none at all.

Share this post


Link to post
Share on other sites
First: You have described factory pattern.

Second: The fact that you're limiting user to launching one instance of an application is completely unrelated to how many CApplication instances there can be.

Third: All the allocation/deallocation problems are exactly why singletons are so hated. It will, at very best, depend on compiler as to when what and how something is de-allocated.

Singleton logger looks like this:

class CLog
{
public:
static CLog *instance( void )
{
return &m_instance;
}
~CLog()
{
// this will be called whenever
}
private:
CLog( const char *filename )
{
// open file for writing, etc.
}
static CLog m_instance;
}

CLog CLog::m_instance( "filename" );





Of course, at this point you'll ask: How do I dynamically determine the filename to write to. You can't. Period. Or you use another singleton from which you obtain it, which will read it from configuration.


class CLog
{
public:
static CLog* instance( const char* filename );
}





Is a factory. It is completely unrelated to singletons in any way. It maintains a state, it caches (or not) instances created, it may or may not be responsible for cleanup.

But most importantly - every call to instance() can return different instance of CLog*. As such, it's unrelated to singleton, which must, on every call to its instance method, return exactly the same instance.

Share this post


Link to post
Share on other sites
Ok I got the main idea.
But anyway I can tell you "Why to do class pure virtual? Just don't create object from this class and there is no need to do it pure virtual." Its the same.

Quote:

All the allocation/deallocation problems are exactly why singletons are so hated.

So if there is no method to track and free(if needed) objects when Singleton destroyed so I prefer not to use it.

Share this post


Link to post
Share on other sites
Quote:
Original post by s.kwee
Ok I got the main idea.
But anyway I can tell you "Why to do class pure virtual? Just don't create object from this class and there is no need to do it pure virtual." Its the same.
No, it isn't. First of all, there's no such thing as a "pure virtual class". You're thinking of an abstract class, which contains pure virtual functions. A class being abstract is a side effect of its having pure virtual functions. And remembering to implement all pure virtual functions in some descendant class of the abstract base class is a lot trickier than remembering to not accidentally create an object.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Quote:
Original post by s.kwee
Ok I got the main idea.
But anyway I can tell you "Why to do class pure virtual? Just don't create object from this class and there is no need to do it pure virtual." Its the same.
No, it isn't. First of all, there's no such thing as a "pure virtual class". You're thinking of an abstract class, which contains pure virtual functions. A class being abstract is a side effect of its having pure virtual functions. And remembering to implement all pure virtual functions in some descendant class of the abstract base class is a lot trickier than remembering to not accidentally create an object.


My fault, I meant abstract class.
The point in my words is that thing weren't developed by formula "and let the singleton to be for fun", if you can force user who use your program to follow this "don't create more that one instance" so there is no need for singleton to be, singleton (not only singleton many things, I use him for example) created to prevent creating more that one object. The same with abstract class for example, that was created in order to prevent creating object of this class.

Any way I don't want to turn this topic into spam or argument topic. I think I got the answer I looked for.
Thanks for everyone who answered :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
The singleton should only be used where it would literally be logically impossible to create more than one.


I've seen this line of argumentation mentioned before, but I regard it as entirely arbitrary.

Singletons are appropriate for both "shouldn't" and "can't" cases concerning multiple instances. Restricting it to only the "can't" case is fairly popular it seems, especially on this board, but I've never seen a good reason to exclude the "shouldn't" case put forth.

Share this post


Link to post
Share on other sites
Quote:
Original post by exwonder
Quote:
Original post by Sneftel
The singleton should only be used where it would literally be logically impossible to create more than one.


I've seen this line of argumentation mentioned before, but I regard it as entirely arbitrary.

Singletons are appropriate for both "shouldn't" and "can't" cases concerning multiple instances. Restricting it to only the "can't" case is fairly popular it seems, especially on this board, but I've never seen a good reason to exclude the "shouldn't" case put forth.


Because the "shouldn't" of today can easily become the "should" of tomorrow without "can't", which can be extremely problematic to deal with in large codebases especially. While you might argue it's okay when you're "certain" it will always be "shouldn't", IMO good coding practices acknowledge that the programmer is fallible -- and thus incapable of making such an assertion accurately.

It's also my opinion that the cost of dealing with those mistakes very very quickly outweighs any benefits of using singletons, resulting in a loss on average. (Aside from this, more of my general rationale against singletons can be found in one of the 4 previous singleton threads made this month alone).

Share this post


Link to post
Share on other sites
Quote:
Original post by exwonder
Quote:
Original post by Sneftel
The singleton should only be used where it would literally be logically impossible to create more than one.


I've seen this line of argumentation mentioned before, but I regard it as entirely arbitrary.

Singletons are appropriate for both "shouldn't" and "can't" cases concerning multiple instances. Restricting it to only the "can't" case is fairly popular it seems, especially on this board, but I've never seen a good reason to exclude the "shouldn't" case put forth.


Yeah, I kind of agree. There are many REALLY good reasons not to use singletons, but "if you don't want multiple, then don't create multiple" is open to interpretation, IMO. If, for instance, creating more than one would yield undefined behaviour or whatever, and if you happen to be working on a platform/library that other developers you aren't directly talking to will be writing code with, you can't just rely on your documentation to inform them that they shouldn't create more than one of something. Then again, most libraries offer ample opportunities to shoot one's self in the foot...

Share this post


Link to post
Share on other sites
Quote:
Original post by Replicon
Yeah, I kind of agree. There are many REALLY good reasons not to use singletons, but "if you don't want multiple, then don't create multiple" is open to interpretation, IMO. If, for instance, creating more than one would yield undefined behaviour or whatever, and if you happen to be working on a platform/library that other developers you aren't directly talking to will be writing code with, you can't just rely on your documentation to inform them that they shouldn't create more than one of something. Then again, most libraries offer ample opportunities to shoot one's self in the foot...


Here's my usual pattern for dealing with that in C++:

//---- HEADER ----
class foo {
public:
foo( ... );
~foo();
};

//---- SOURCE FILE ----

namespace { foo* instance = 0; }
foo::foo( ... ) { assert(!instance); instance = this; }
foo::~foo() { assert(instance==this); instance = 0; }



For code to be used out-of-house, simply upgrade the first assert to a more robust error reporting mechanism. By doing this, I won't have to break any existing code (as I would with the singleton) if I added support for multiple instances at a later date.

Note that I avoid depending on "instance" for anything but this error checking within foo, and never expose it to anything outside of foo's implementation details.

Share this post


Link to post
Share on other sites
Do people actually read GoF and latch onto singleton, and nothing else, as some kind of feel-good global or is there some tutorial out there suggesting people should be using it? I don't get where relatively new users of C++ are finding this thing.

To be constructive: Singletons. All the threads end up saying roughly the same things.

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
IMO good coding practices acknowledge that the programmer is fallible


At the risk of taking your quote out of context... this is the exact reason I'd want to regulate the "only create one instance" rule in code that's only intended to be instantiated once. I see you've posted alternate code for this, which is interesting and I'll have to look at it more carefully later.

There's always the possibility that you'll need a singleton to become a non-singleton, but if you restrict singleton usage to "managers", this usually doesn't come up. We use singletons heavily at work, for good or evil, and I don't recall ever having to change one because everyone "gets" them and makes reasonably good decisions about when there's only going to be one thing.

Now, aside from the "maybe you'll need more than one" argument, which is a very valid consideration (although argued poorly in most cases I've seen), most of the people on this board that I've read so far are arguing against globality in general, rather than singletons... which makes me look at this board a little strangely when half the people in a thread are saying you should use a global instead. It all seems like a religious argument, similar to "don't use goto zomg it's so bad." Like people are opposed to using singletons just because someone told them it would make them a better programmer.

Globality and single-instantiation are both interesting topics of debate and good discussions to have when talking about clean/cleaner/cleanest code. I don't get the feeling that any of the threads I've read on singletons from this board so far (admittedly, not all of them) take either of these issues seriously and are just "don't use singletons"... accompanied by a couple paper-thin explanations of why not to use singletons, sometimes hinting at valid issues, sometimes not.

Share this post


Link to post
Share on other sites
What I've noticed:
1) Globals are generally argued as "a better alternative then singletons" since the person generally is only interested in the "global access" aspect of a singleton and not the single instance aspect.

2) Explicitly pointing out dependencies in code by passing things as parameters is argued as a better alternative to globals since it reduces the chances of introducing unwanted dependencies.

The problem, I think, comes from inexperienced people reading these arguments so often that they start to regurgitate them without really understanding the argument or even questioning its validity and so the argument gradually gets distorted by them reinterpreting it and restating it in there own words (which since they don't fully understand it will probably result in them inadvertently changing the meaning).

Share this post


Link to post
Share on other sites
Quote:

Globality and single-instantiation are both interesting topics of debate and good discussions to have when talking about clean/cleaner/cleanest code. I don't get the feeling that any of the threads I've read on singletons from this board so far (admittedly, not all of them) take either of these issues seriously and are just "don't use singletons"... accompanied by a couple paper-thin explanations of why not to use singletons, sometimes hinting at valid issues, sometimes not.


Single-instantiation is nothing more than an excuse for singleton use. The real reason singletons are used are globality, and nothing else. Is single-instantation really the issue? Fine, then use the singleton pattern, but use Singleton::GetInstance() *just once*, and then pass the reference where needed. If GetInstance() is called twice, an exception is thrown. That way, you have:

a)Ensured that noone creates more than 1 instances.
b)No global access: modules that don't need the instance have no access to it, thus eliminated in a potential bug-hunt regarding the singleton,or crazy situations where your SoundManager can access your TextureManager.

Now, who uses singletons like that? Noone. Why? Because the reason everyone "loves" them is globality. Nobody really gives a crap about single-instantiation. And I say, if you want globality, just use a global variable or function and be done with it. That's what I do.

Share this post


Link to post
Share on other sites
Quote:
Original post by mikeman
Now, who uses singletons like that? Noone. Why? Because the reason everyone "loves" them is globality. Nobody really gives a crap about single-instantiation. And I say, if you want globality, just use a global variable or function and be done with it. That's what I do.


I care about single-instantiation and global access. If I'm making a singleton, I want both. There are two possible problems with this:

1) I shouldn't be wanting single-instantiation.

Ok, maybe not. But usually arguments against this are kind of poor. "What if you need another _____?" usually doesn't work as an argument if singletons are used appropriately. This should be a case-by-case determination, not a firm and fixed rule.

2) I shouldn't be creating bad coupling through usage of a global.

Ok, maybe not, but this isn't the same discussion, is it? If singletons are bad because globals are bad, then "just make one global instance" doesn't work as a suggestion.

The end result of both points seems to be more like "think extra carefully about using a singleton for this", rather than "don't use singletons."

I don't really want to start a flame war about this... you guys have enough threads about it on this forum anyway. I just want to point out that what seems to be happening here is that you have one side shouting "singletons are bad because you might want another instance" and the other side shouting "singletons are bad because you don't want globals."

Neither side is telling the whole story, but all people seem to be hearing is "singletons are bad" from both sides. Singletons can be bad... it depends on what you want to use them for and the codebase you're working with.

Share this post


Link to post
Share on other sites
Quote:
Original post by exwonder
Quote:
Original post by MaulingMonkey
IMO good coding practices acknowledge that the programmer is fallible


At the risk of taking your quote out of context... this is the exact reason I'd want to regulate the "only create one instance" rule in code that's only intended to be instantiated once. I see you've posted alternate code for this, which is interesting and I'll have to look at it more carefully later.


I won't disagree. The problem with the singleton is that it doesn't just create this rule, it also encourages dependence upon that rule to the point of making it very hard to rescind that rule by encouraging global access, even in situations where global access isn't terribly desirable.

For the cases where you really are certain it's okay to build your code around the assumption of a globally accessible single instance, you have simpler alternatives to the singleton still. A plain, normal global, or even just a set of free functions -- not everything has to be an object (or things can be part of the implied application object context, depending on your PoV).

Share this post


Link to post
Share on other sites

This topic is 3837 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this