What I use where (some) other ppl use singletons.

Started by
17 comments, last by JohnBolton 18 years, 3 months ago
In many cases, it is necessary to provide global instance of some class. In such case, singletons are usually used. IMO it is wrong because singleton is made to do two things: 1: define global instance accessible from elsewhere edit: that is (usually)created on first use 2: forbid creation of other instances second part is necessary only in device drivers (when two classes can not coexist) It is not wise to implement first _and_ second in any case when you in fact just need first alone. So, i use that simple thing if i want global object:

// edit:
// whole mess is necessary to solve construction order problems - this thing is
// constructed on first use so you can use it from other constructors (but not
// recursively).

#define DECLARE_GLOB_OBJECT(Type,Name) \   
  Type *Name();

#define DEFINE_GLOB_OBJECT(Type,Name) \   
  Type *Name(){ \   
    static Type instance; \   
    return &instance; \   
  };

// version that allocates on heap:
#define DEFINE_GLOB_OBJECT_HEAP(Type,Name) \     
  Type *Name(){ \   
    static std::auto_ptr instance(new Type); \     
    return instance; \   
  };

// when need something fancier, define it manually.








The idea is that implementation details* is hidden from client code - everything uses uniform GlobBlaBla() like things. So even if you have to use singletons (are coding something very low level so few instances can't coexist), it (IMO) could be good idea to create another DEFINE_GLOB_OBJECT_SINGLETON that uses singleton - this way implementation details about possibility of coexistence of few instances is hidden from code that uses the object. (*if few instances of class could coexist of not it is low level implementation details. Really low level, i.e. at level of working with hardware almost directly) [Edited by - Dmytry on December 30, 2005 6:22:52 AM]
Advertisement
But isn't the second point an essential part of the definition of a singleton?
Otherwise it really is just a global class instance that suffers from the same deficiencies as a singleton (e.g. order of destruction).





Wouldn't it be easier to just have the class instantiated once and then have a pointer to that class passed around?
<a href="http://ruggles.hopto.org>My Personal Website
Quote:Original post by darookie
But isn't the second point an essential part of the definition of a singleton?
Otherwise it really is just a global class instance that suffers from the same deficiencies as a singleton (e.g. order of destruction).

First: this is just what to do if you _need_ 1 but do not _need_ 2 . In such case, you need to provide global entry point, but don't need to limit to one instance. That's not where singleton should be used. But in reality many programmers use singletons in such cases, and practically implement 1 (what they need) AND 2 (what they do not need or even what is bad for their code).
The code I posted is equivalent to singleton but is
a.) simpler because it does not do 2
b.) it actually could be made to do 2 if ever needed without breaking the code that accesses the global.

For example, that's what you should be using for logging class. You could need several instances of logging class, but in beginning need just one.
Quote:Original post by ChaosX2
Wouldn't it be easier to just have the class instantiated once and then have a pointer to that class passed around?

it is theoretically good, but in really many cases you can not do that, and in such cases programmers usually use singletons even if they absolutely don't need "single" part.
I don't understand. Your implementation is a Singleton. Also, how is it better (or different) than this implementation?
    class foo    {    public:        static foo * Instance()        {            static foo instance;            return &instance        }    private:        foo();        ~foo();        foo( foo const & );        foo operator =( foo const & );    }; 
Also, if you need define a global instance accessible from elsewhere but don't care it being unique, you could just do this:
   extern bar global_bar; 
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
JohnBolton: i explained how it is diffferent. My instance absolutely is not Singleton
Maybe it should be called "ton" pattern, i don't know.
Example:
.h
DECLARE_GLOB_OBJECT(Logger,GlobPhysicsThreadLog)
DECLARE_GLOB_OBJECT(Logger,GlobRenderingThreadLog)


.cpp
DEFINE_GLOB_OBJECT(Logger,GlobPhysicsThreadLog)
DEFINE_GLOB_OBJECT(Logger,GlobRenderingThreadLog)

That's example of creating two instances of class Logger. Without modifying class itself. That are acessible in uniform manner. If Logger is singleton, it is not possible. But you may need several logs (esp. when working on multithreading app.)

Singletons have their use: when you are positively sure you can not and will never need to have several instances coexisting.
Quote:Original post by Dmytry
JohnBolton: i explained how it is diffferent.
Example:
.h
DECLARE_GLOB_OBJECT(Logger,GlobPhysicsThreadLog)
DECLARE_GLOB_OBJECT(Logger,GlobRenderingThreadLog)


...
DEFINE_GLOB_OBJECT(Logger,GlobPhysicsThreadLog)
DEFINE_GLOB_OBJECT(Logger,GlobRenderingThreadLog)

That's (almost) same as
extern Logger GlobPhysicsThreadLog;extern Logger GlobRenderingThreadLog;...Logger GlobPhysicsThreadLog;Logger GlobRenderingThreadLog;

The only difference is that with your approach the instances get intialised upon first use...

EDIT: Blast! John was faster [smile]
Quote:Original post by JohnBolton
Quote:Original post by Dmytry
JohnBolton: i explained how it is diffferent.
Example:
.h
DECLARE_GLOB_OBJECT(Logger,GlobPhysicsThreadLog)
DECLARE_GLOB_OBJECT(Logger,GlobRenderingThreadLog)


...
DEFINE_GLOB_OBJECT(Logger,GlobPhysicsThreadLog)
DEFINE_GLOB_OBJECT(Logger,GlobRenderingThreadLog)


I see. I would do it this way, then:
    .h    extern Logger GlobPhysicsThreadLog;    extern Logger GlobRenderingThreadLog;        .cpp    Logger GlobPhysicsThreadLog;    Logger GlobRenderingThreadLog; 

three words: initialization order problems. The thing that singleton is intended to solve.
With local static, it is created when execution goes over it.
Of course it could still have finalization order problem but them is rarer to be so bad.
edit: blast, darookie was faster[grin]

Actually, i'm is using it for class where i register other classes during initialization, using something like
register_class<MyClassFactory> blabla("MyClass");
(done with macroses)
The register_class will call GlobClassRegistry()->AddClass(MyClassFactory,"MyClass")
so I can create classes by name (i'm doing data driven architecture)
Quote:Original post by darookie
...
The only difference is that with your approach the instances get intialised upon first use...

EDIT: Blast! John was faster [smile]


But I deleted my post because what you wrote pointed out what I was overlooking, so you can have full credit.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!

This topic is closed to new replies.

Advertisement