Sign in to follow this  
JinJo

is there a way to get rid of clas::getSingleton().functionCall

Recommended Posts

JinJo    100
I was just wondering if there was a way to call functions from a singleton class without having to call getSingleton as part of the function call? Say for example: Log::GetSingleton().Write("log this or that"); well I have the log class a singleton so that it can be used anywhere in the program but I dont want to have to keep writing getSingleton or have to make the user aware that it is a singleton and frustrate them by having to type that all the time.

Share this post


Link to post
Share on other sites
jyk    2094
Quote:
Original post by JinJo
I was just wondering if there was a way to call functions from a singleton class without having to call getSingleton as part of the function call?

Say for example:
Log::GetSingleton().Write("log this or that");

well I have the log class a singleton so that it can be used anywhere in the program but I dont want to have to keep writing getSingleton or have to make the user aware that it is a singleton and frustrate them by having to type that all the time.
If Log is a singleton, you probably shouldn't try to hide that fact from the user of the class.

You could shorten the function name to Get(), which might be a little more convenient. Or, you could use a different pattern or model, such as a monostate or a global object.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
well Log::ref() and Log::ptr() dont take much writing but you could always define it in the header after the class.
Quote:

#define g_log Log::GetSingleton()

Share this post


Link to post
Share on other sites
Aardvajk    13207
Quote:
Original post by Anonymous Poster
well Log::ref() and Log::ptr() dont take much writing but you could always define it in the header after the class.
Quote:

#define g_log Log::GetSingleton()


Sure. Why not. Let's pretend we are not using a global by using a singleton, then pretend we are not using a singleton by using a define. [smile]

I'd agree with jyk that a monostate approach might be suitable here. Equally, GetSingleton is a bit of a verbose name for the get method.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
"...Let's pretend we are not using a global by using a singleton..."

That is not the purpose of a singleton, although I do agree that a monostate is a much better alternative.

Share this post


Link to post
Share on other sites
Aardvajk    13207
I still don't really understand the advantage of using a singleton over a global. It doens't seem to me to be any different. Can anyone explain what the advantages are, because I feel I have a bit of a hole in my understanding.

I'm not actually convinced a monostate would really offer any advantages here either. If you only have one log, a singleton or monostate don't seem to be any better than a global. If you might need multiple logs in the future, the singleton or monostate become useless.

I'm probably missing something fundamental here.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
I still don't really understand the advantage of using a singleton over a global.

A global is a global instance of which may it not be the only one, a singleton is a global instance of which there can only be one. Its a creation pattern which is abused.

Share this post


Link to post
Share on other sites
OrangyTang    1298
Quote:
Original post by EasilyConfused
I still don't really understand the advantage of using a singleton over a global. It doens't seem to me to be any different. Can anyone explain what the advantages are, because I feel I have a bit of a hole in my understanding.

Singletons give people a warm fuzzy feeling that they're using design patterns, and everyone knows that patterns are always good, right?

Share this post


Link to post
Share on other sites
Aardvajk    13207
Quote:
Original post by OrangyTang
Quote:
Original post by EasilyConfused
I still don't really understand the advantage of using a singleton over a global. It doens't seem to me to be any different. Can anyone explain what the advantages are, because I feel I have a bit of a hole in my understanding.

Singletons give people a warm fuzzy feeling that they're using design patterns, and everyone knows that patterns are always good, right?


That seems a sufficient justification. We all need warm fuzzy feelings sometimes.

[EDIT] Actually, I've just remembered that a singleton does offer an advantage of being able to control the point of construction to point of first use. I remember reading Scott Meyers on this.

Doesn't seem of much benefit for a log file but I guess they are not completely useless.

[Edited by - EasilyConfused on November 24, 2006 4:33:03 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
lol @ OrangyTang
"everyone knows that patterns are always good, right?"
I don't, know I have some horrendous christmas jumpers :)

Share this post


Link to post
Share on other sites
Spoonbender    1258
Quote:
Original post by EasilyConfused
[EDIT] Actually, I've just remembered that a singleton does offer an advantage of being able to control the point of construction to point of first use. I remember reading Scott Meyers on this.

Doesn't that take control of point of construction *away*? You don't know when it'll be constructed, since you might not be able to tell where it's first used.

Share this post


Link to post
Share on other sites
janta    345
How about this approach ?

template <class T> class Singelton_Ptr
{
private:
T* ptr;

public:
T* operator->() const
{
return T::GetSingleton();
}

// Anything else you fancy...
};
// -----------------------------
SomeClass
{
public:
// Public stuff

private:
static SomeClass* singleton;
static SomeClass* GetSingleton();
// ...
};
// -----------------------------
extern Singleton_Ptr<SomeClass> gSomeClassSingleton;





However as jyk said, you hide the fact that gSomeClassSingleton (well, I think that given the name it's quite obvious but...) which might be a bad idea.

Share this post


Link to post
Share on other sites
See, I personally believe that Singletons are an evil creation by the Gang of Four designed to increase the size of our source files and decrease the readability of our code. :p

Seriously though, guys: design patterns are not the be all and end all. Sure some of them may be useful in some situations, but that book really isn't programming dogma. Just make your best judgment on what you need in your current situation.

If a global variables works fine for you and it's well documented that it's a global variable that does XYZ, then you should be okay. Now if you have 100 people on this project and you require some heavily object-oriented abstraction then singletons or another solution might be a better idea.

Just use what's appropriate for the situation and think for yourself. Never let an advocate of one thing convince you of it without putting any thought into it first.

Share this post


Link to post
Share on other sites
rip-off    10976
I used to have singletons when I first heard of them.

Now I try remove dependancies of classes rather than make singletons.

Once a class has little or no dependancies, controlling creation and destruction becomes much easier.

My log is more a monostate, it is just a vector of things that accept log output.

All I need to do to allow the log to be useful is to associate a simple file stream wrapper with my log. When my application gets to the point that it has its graphics setup, it associates a quake-style console log with the log.

My log call is just "Log(string)", which expands to include both __FILE__ and __LINE__.

The global vector is not publically accessible, being limited to file scope ( why bother making some monostate class when I can hide stuff in the source file in an anonymus namespace [smile] ), only the addLog() and removeLog() functions are. As my program contains no globals that are constructed before main(), I can guarentee that my log vector will be ready when someone comes along to try and log something.

Share this post


Link to post
Share on other sites
Aardvajk    13207
Quote:
Original post by Spoonbender
Quote:
Original post by EasilyConfused
[EDIT] Actually, I've just remembered that a singleton does offer an advantage of being able to control the point of construction to point of first use. I remember reading Scott Meyers on this.

Doesn't that take control of point of construction *away*? You don't know when it'll be constructed, since you might not be able to tell where it's first used.


Well, I don't know much about this really, but I remember reading about what I believe is called the Meyers singleton which would look like:


class Xyz
{
public:
Xyz(){ /* expensive constructor */ }

void Call(){ }
};

Xyz &XYZ()
{
static Xyz X; return X;
}

// in use
void f()
{
XYZ().Call(); // use as if it was the object, kind of thing
}


The C++ rules mean that the static object won't get its constructor called until the flow first passes through the function, so the constructor isn't called until the first time the object is used, and if it is never used in a particular run, the constructor is never called at all.

I think this maintains the main point of a constructor - that an object can never be used when in an uninitialised state - but I agree there are potential problems with not knowing exactly when it is constructed. Then again you have that issue anyway with global objects across different translation units and this does address that problem.

I've never really found a use for it myself, but I understand Meyers to be quite an authority on C++ so I assume it has been quite well thought through.

Share this post


Link to post
Share on other sites
JinJo    100
Ok, I will explain a bit why I want to use a singleton in my Log class (though this monostate sounds like a good idea?)

I have a project where currently I am the only person working on it but within the next few months others will.
There are a lot of interface/plugins in the form of different dll projects, such as the different render api and input api's etc.

Now the main engine is an exe and runs a game from a script which loads levels logic and resources.
The log is first constructed in the engine init function (yep even though it's a singleton I am using a public construtor, is that that bad?

Now I want to just be able to include log.h in any file and use it without having to construct it etc etc.

so i have the ability to do log->getsingleton().write("blah");
even within the dll's, though I had to do dll export in the log class and singleton (dont hate me but im starting to like java for the fact that i dont even need to include the log.h file ;)

maybe your right to say that the fact that its a singleton shouldnt be hidden from the user. However very little game code will be written in c++, its all scrpts and the log and renderer etc are exposed to the scripting language.

I just feel that log, in my project should be seen as an engine utility that can be used anywhere and not worry about whats going on with it.

Thanks for some insight though, any other suggestions?

Share this post


Link to post
Share on other sites
rip-off    10976
Quote:
Original post by JinJo
Ok, I will explain a bit why I want to use a singleton in my Log class (though this monostate sounds like a good idea?)

I have a project where currently I am the only person working on it but within the next few months others will.
There are a lot of interface/plugins in the form of different dll projects, such as the different render api and input api's etc.

Now the main engine is an exe and runs a game from a script which loads levels logic and resources.
The log is first constructed in the engine init function (yep even though it's a singleton I am using a public construtor, is that that bad?

Now I want to just be able to include log.h in any file and use it without having to construct it etc etc.

so i have the ability to do log->getsingleton().write("blah");
even within the dll's, though I had to do dll export in the log class and singleton (dont hate me but im starting to like java for the fact that i dont even need to include the log.h file ;)

maybe your right to say that the fact that its a singleton shouldnt be hidden from the user. However very little game code will be written in c++, its all scrpts and the log and renderer etc are exposed to the scripting language.

I just feel that log, in my project should be seen as an engine utility that can be used anywhere and not worry about whats going on with it.

Thanks for some insight though, any other suggestions?


As functions are easier to export than classes, a monostate of some kind could work quite well for you.

I think that the earlier you start the log the better, in my application the log is the first thing I create. The only dependancy I have is std::ofstream.

What are your logs dependancies?

Share this post


Link to post
Share on other sites
ToohrVyk    1595
Quote:
Original post by Spoonbender
Doesn't that take control of point of construction *away*? You don't know when it'll be constructed, since you might not be able to tell where it's first used.


Actually, it doesn't. The fact is that you only want the object to be constructed before it's used. With global variables, you might run into trouble if one global variable constructor tries to use a global variable which has not been initialized yet. With singletons, you know by design that the instance-getter will return a fully constructed instance. Besides, if your design is sheepishly stupid, you can also detect circular references from constructor to constructor if they happen, simply by following the stack trace once the program has crashed (assuming that your instance-getter is built correctly).

As for this particular problem, I see no reason why you couldn't use the exact same design as std::cerr.

Share this post


Link to post
Share on other sites
JinJo    100
my dependncies are:

#include <fstream>
#include <cassert> (only as my singleton has classes that need over ridden in classes that have dll export (sounds like i'm doing something wrong eh lol)

#include "Singleton.h" (the only dependancy this has is assert)

i also include a class called misc.h in log which is used for generating message boxes, it has a cross platform function called messagebox that acts like the messagebox on windows.

I am thinking of going with the monostate pattern (sounds quite clean) now or simply a global variable (would this variable be best put in the log.h file and created in log.cpp?)

Share this post


Link to post
Share on other sites
NotAYakk    876

GlobalLog* GLog() {
return GlobalLog::GetSingleton();
}


So now you have

GLog()->Write("log this or that\n");


Note that a sufficiently complex system will want more than just a simple logging function that takes strings.

You'd want enter/exit function classes, object lifetime logging classes, categories of messages, and possibly some units of your logger should use "real time" logging (guaranteed not to allocate memory or write to disk) and other parts should use "safe" logging (gets the data out of the process space before returning) and other parts should use "buffered" logging (builds up a buffer of a bunch of log messages, and writes them to disk in an idle thread).

Then again, that is only for sufficiently complex systems. Your game doesn't have to be sufficiently complex. :)

Share this post


Link to post
Share on other sites
JinJo    100
thanks for that, looks like it would solve my initial problem/irritance, still I might consider not using a singleton at all.

I must note that my log can take different categories of messages and targets etc. The pattern or implementation used wouldnt really cause trouble to adding other features.

Share this post


Link to post
Share on other sites
Skizz    794
Alternatively, a pimpl style mechanism could work:

// FILE: log.h

class Log
{
public:
static void Write (std::string &text);
// etc
private:
static Initialise (void);
static class TheLogObject
*m_log;
};

// FILE: log.cpp

#include "TheLogObject.h"

TheLogObject
*Log::m_log = 0;

void Initialise (void)
{
if (m_log == 0)
{
m_log = new TheLogObject;
}
}

void Log::Write (std::string &text)
{
Initialise ();
m_log->Write (text);
}

// FILE: TheLogObject.h

class TheLogObject
{
public:
void Write (std::string &text);
};


To use the Log:

Log::Write (message);


Skizz

Share this post


Link to post
Share on other sites

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