Archived

This topic is now archived and is closed to further replies.

Need "simple" singleton class example

This topic is 5139 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

I want to start using singleton classes, but wherever i look the examples include other stuff that i cannot differentiate from the actual singleton class code. So if someone could provide an example or modify this code here to be a singleton class, would be really great.
class Apple {
public:
   Apple()
   {
   }

   ~Apple()
   {
   }
   
   void myMethod()
   {
   }

private:
};

thanks,

Share this post


Link to post
Share on other sites

class Apple
{
private:
// Prevent creation of Apple instances from client code

Apple() { /* constructor code */ }

// Disable copying (and pass-by-value)

Apple(const Apple&); // no implementation

Apple& operator=(const Apple&); // no implementation


// The instance will have to be destroyed when the

// program finally terminates.

~Apple() { /* destructor code */ }

public:
// This is where you get your singleton instance from

static Apple* GetInstance()
{
static Apple instance;
return &instance;
}
};

Apple* ptr = Apple::GetInstance();


edit: Curse you, SiCrane !


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]


[edited by - Fruny on November 9, 2003 6:09:20 AM]

Share this post


Link to post
Share on other sites
Ack, no. If you use a Meyer''s Singleton to manage lifetime and you return a pointer from your instance function, make the destructor non-public so that the client isn''t tempted to delete the returned pointer.

Share this post


Link to post
Share on other sites
quote:
Original post by SiCrane
Ack, no. If you use a Meyer''s Singleton to manage lifetime and you return a pointer from your instance function, make the destructor non-public so that the client isn''t tempted to delete the returned pointer.


My original code returned a reference, but then I thought about the hassle of having him actually use reference ''variables''. So, yeah. Once again, *sigh*.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
quote:
Original post by SiCrane
Ack, no. If you use a Meyer's Singleton to manage lifetime and you return a pointer from your instance function, make the destructor non-public so that the client isn't tempted to delete the returned pointer.



i get this error message if i do that
quote:

error C2248: 'g::~g' : cannot access private member declared in class 'g'
see declaration of 'g::~g'



so i put the destructor in the public part and it did, is there anything else i should do instead?

edit:

just one more thing, how would i use the class,
i got this error when i tried doing it like this
Apple myApple;

quote:

error C2248: 'D3D::D3D' : cannot access private member declared in class 'D3D'
see declaration of 'D3D::D3D'



[edited by - johnnyBravo on November 9, 2003 6:44:49 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by johnnyBravo
just one more thing, how would i use the class,
i got this error when i tried doing it like this
Apple myApple;



That''s exactly the point behind using a Singleton, to prevent you from ever doing that. Use the value returned by Apple::GetInstance() instead.



[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
What compiler are you using? All the ones I tried will let the destructor be private.

With the version of the Singleton that Fruny described, you always access the Apple through Apple::GetInstance(). You don''t need to create it or allocate it. The Apple will construct itself the first time you call Apple::GetInstance().

Share this post


Link to post
Share on other sites
Well, you could always do


class Apple
{
private:
// Prevent creation of Apple instances from client code

Apple() { /* constructor code */ }

// Disable copying (and pass-by-value)

Apple(const Apple&); // no implementation

Apple& operator=(const Apple&); // no implementation


public:
// The instance will have to be destroyed when the

// program finally terminates.

~Apple() { /* destructor code */ }

// This is where you get your singleton instance from

static Apple& GetInstance()
{
static Apple instance;
return instance;
}
};

Apple& ref = Apple::GetInstance();


The usual caveats about references apply.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
quote:
Original post by johnnyBravo
hmm isnt that just the same as the other one? cept with the destructor in public which i had to do anyway?



No, notice how the * have been changed into & .

quote:

one more question, is there a singleton way that i can call it like

Apple myApple;



Not *quite* a singleton, but it does what you want:

Apple.h

class Apple_Impl;

class Apple
{
static Apple_Impl* instance;
static unsigned long reference_count;
public:
Apple();
Apple(const Apple&);
Apple& operator=(const Apple&);
~Apple();

int MyMethod();
}


Apple.cpp
   
class Apple_Impl
{
public:
int MyMethod() { /* code */ }
};

Apple_Impl* Apple::instance = 0;
unsigned long Apple::reference_count = 0;

Apple::Apple()
{
if(!reference_count)
{
instance = new Apple_Impl;
reference_count = 1;
}
}

Apple::Apple(const Apple&)
{
++reference_count;
}

Apple& Apple::operator=(const Apple& rhs)
{
if( &rhs != this ) ++reference_count;

return *this;
}

Apple::~Apple()
{
--reference_count;
if( !reference_count )
{
delete instance;
instance = NULL;
}
}

int Apple::MyMethod()
{
return instance->MyMethod();
}


It's a singleton, but ... well, it's much, much heavier.
You essentially delegate all your calls to a hidden implementation class.

There is also a difference in design here : the singleton is destroyed when the last reference to it goes away. It's a design decision... if you declare one Apple global variable, you'll be ok. If you only create temporary Apples, you'll be in trouble.

Also, make sure not to hand out pointers or references to the internal Apple_Impl, or people could cheat and be surprised when they are left with a dangling pointer

And yes, I do believe it is necessary to put all that stuff in a CPP file.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]


[edited by - Fruny on November 9, 2003 7:37:03 AM]

[edited by - Fruny on November 9, 2003 8:13:30 AM]

Share this post


Link to post
Share on other sites
Or, using the first "Apple* ptr = Apple::GetInstance();" code, you could do :

class AppleWrapper
{
Apple* instance;
public:
AppleWrapper() : instance( Apple::GetInstance() ) {}

Apple& operator*() { return *instance; }
Apple* operator->() { return instance; }
};

AppleWrapper wrapper;
wrapper->MyMethod();


Note - you''ll also probably need the const versions of the operators.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
quote:
Original post by quant
How is that a singleton? You can construct multiple instances of both Apple and Apple_Imp1


It's not a Singleton, it's a Monostate (if you want to argue about such things), but the end result is about the same.

You can construct multiple instances of Apple. But, unless you do so in the Apple.cpp source file, you can't create multiple Apple_Impl. Which is why I emphasised the separation.

And all instances of Apple really delegate all the work to the one and only Apple_Impl.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]


[edited by - Fruny on November 9, 2003 8:04:33 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Fruny


Apple::~Apple()
{
--reference_count;
if( !reference_count ) delete instance;
instance = NULL;
}




Another problem here, everytime a destructor is called when reference_count isnt equal to 1, you leak memory into the free store(because your setting instance to NULL whether reference_count is equal to 0 or not).

I think you meant


Apple::~Apple()
{
--reference_count;
if( !reference_count )
{
delete instance;
instance = NULL;
}
}


[edited by - Jingo on November 9, 2003 8:13:34 AM]

Share this post


Link to post
Share on other sites

class Apple
{
private:
Apple(){}
public:
~Apple(){}
void myMethod(){}
static Apple *GetInstance(void)
{
static Apple Instance;
return &Instance;
}
};
//

#define GAPPLE Apple::GetInstance()


Then to use it just call:
GAPPLE->myMethod();

That''s one way I use, and it works fine. Game Programming Gems I shows different methods of doing this (And better ways). If you want to see it, enginuity 2 shows the one from the book. You can find it here, look toward the bottom.

To use that one, setup the class like this:

class Apple : public Singleton<Apple>
{
private:
Apple(){}
public:
~Apple(){}
void myMethod(){}
};
//

#define GAPPLE Apple::GetSingleton()


Then to use it just call:
GAPPLE.myMethod();

Both ways work nice though.
Best of luck,

-UltimaX-

"You wished for a white christmas... Now go shovel your wishes!"

Share this post


Link to post
Share on other sites
Hey the main reason i want to use singletons is that they can be called from anywhere and used anywhere.

But i just realised i may need more than one of the same class to store varying data. Is there a way to do this while still being able to call the class from anywhere and use it anywhere?

Share this post


Link to post
Share on other sites
... Erm I don't think so. Not more than 1 instance. For that just make the constructor public and create a seperate class.

-UltimaX-

"You wished for a white christmas... Now go shovel your wishes!"

[edited by - UltimaX on November 9, 2003 8:29:39 AM]

Share this post


Link to post
Share on other sites
Here is my singleton:


class CBla
{
public:
CBla()
{
assert(pBla == NULL); //this is a singleton!

pBla = this;
}
~CBla()
{
pBla = NULL;
}
};

CBla *pBla = NULL; //global var



Design purists would start to cry when they see this >
I dont care. Its clean and simple.

When you need to work with someone-elses classes... Would you like, to first study his singletons (and probably loads of other complex and not really functional stuff) ?

"do more with less"

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by baskuenen

class CBla
{
public:
CBla()
{
assert(pBla == NULL); //this is a singleton!

pBla = this;
}
~CBla()
{
pBla = NULL;
}
};

CBla *pBla = NULL; //global var





Heh, this is a lot of things, but it certainly isnt a singleton
in any shape or form.

A singleton is a class which can only have one instance, that has a global point of access to it.

The global point of access is where the simularities between your .. ''thing'' and a singleton end. Whats stopping someone from doing this..


CBla first_instance;
CBla second_instance;
CBla third_instance;





Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Eek.. must be spreading

That should be


CBla first_instance;
CBla second_instance(first_instance);
CBla third_instance(first_instance);


I.e. using the implicitly declared copy constructor

Share this post


Link to post
Share on other sites
quote:
But i just realised i may need more than one of the same class to store varying data. Is there a way to do this while still being able to call the class from anywhere and use it anywhere?

You don't want a singleton then. Singletons enforce a single instance of a class that is accessible anywhere.

I don't really see the point of a simple singleton class, either, it is just a class with ctor/dtor private and a method called instance() that returns a reference. Loki's Singleton wrapper is meaningful because he at least has templated policy classes that can make the singleton thread-safe and other cool things. The author of that is brilliant.

(singleton tirade)
Resist the urge to use globals/singletons until you have no other options. Your back should be to the wall (proverbially) and it should be very clear that you need a single instance, plus global accessibility (e.g. clients shouldn't have to concern themselves with providing the information for elegance).

Singletons do rock in that a Meyers singleton won't be instantiated unless it is actually needed. To get around lifetime issues, I use a LifetimeManager that manages the dependencies, I recommend people do the same if its possible for singletons to be dependent on one another.

Just because a singleton is a design pattern doesn't mean it should be everywhere. Just because you need only one instance of a class doesn't mean it should be a singleton. I see in a bunch of articles where people make stuff singletons, and have to ask why. Fighting with initialization/destruction order sucks. Enforcing singletons in an application spread across DLLs forces you to fight either DLL memory boundaries or be dependent on the runtime library being linked in at runtime, and therefore present on the user's system.

Singletons seem like a hack to support something that C++ has trouble expressing 'natively.' I cannot think of a better way to do it than we have right now. Issues with separate heaps/runtime libraries make things far more difficult than they need to be.

[edited by - antareus on November 9, 2003 2:55:36 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
Eek.. must be spreading

That should be


CBla first_instance;
CBla second_instance(first_instance);
CBla third_instance(first_instance);


I.e. using the implicitly declared copy constructor


Well, good point. I would hope logic prevents any user doing anything like that
Without viewing all of the current possibilities in singleton creation (in this thread and otherwise), I could solve it by adding a private copy-constructor and =operator.

But I''m still putting my hope into an extremely good logical design of all my classes, instead of building singletons.

You''re probably thinking what a lame answer this is.
But my concern is.. when I start coding complete singletons and other ''design-technical'' stuff... where does it end?!
For example: a portable typeid-class where all other classes are derived from. Or maybe something with streaming files/memory/sockets/input/... (like delphi does more or less).
Streaming in and out all variables from any class.. maybe very nice, but if my teammates saw me do that.. it''ll not improve my popularity

One small advantage to my hacked singleton is that I control when this class gets con- and de-structed. So far this has proven to be very welcome!


I guess when choosing how to implement your singleton class, it''s also a matter of taste.

Share this post


Link to post
Share on other sites
quote:

Resist the urge to use globals/singletons until you have no other options. Your back should be to the wall (proverbially) and it should be very clear that you need a single instance, plus global accessibility (e.g. clients shouldn't have to concern themselves with providing the information for elegance).


I totally agree with you. Once newbies learn about singeltons they start using them for everything when their not needed (I used to do that all the time). And if you have to use a singelton, don't use the global reference, pass it to the function/class. ie, don't do this:

class Singelton{...};

void doStuff()
{
singelton::get().doStuff();
}

int main()
{
doStuff();
return 0;
}

do this:

class Singelton{...};

void doStuff(Singelton& s)
{
s.doStuff();
}

int main()
{
doStuff(Singelton::get());
return 0;
}


[edited by - brassfish89 on November 9, 2003 6:35:02 PM]

Share this post


Link to post
Share on other sites