Reputation: 64266
I have such singleton structure:
// Hpp
class Root : public boost::noncopyable
{
public:
~Root();
static Root &Get();
void Initialize();
void Deinitialize();
private:
Root(); // Private for singleton purposes
static Root *mInstance;
Manager1 *mManager1;
Manager2 *mManager2;
};
// Cpp
Root *Root::mInstance = nullptr;
Root::Root()
{
mInstance = this;
// Managers are using `mInstance` in their constructors
mManager1 = new Manager1();
mManager2 = new Manager2();
mInstance->Initialize();
}
Root::~Root() { delete mManager1; delete mManager2; }
Root &Root::Get()
{
if (mInstance == nullptr) mInstance = new Root();
return *mInstance;
}
void Root::Deinitialize()
{
delete mInstance;
}
And here is the usage of this singleton:
Root::Get();
// Some code calling related to mManager1 and mManager2
Root::Get().Deinitialize();
The questions are:
mInstance
(call dtor manually). Because the user could forget to call Deinitialize()
method.Upvotes: 1
Views: 1616
Reputation: 4543
Have you considered what would happened if your singleton wasn't deleted at all?
By definition, a singleton is an single object shared by many client objects as the clients tend to come and go. Most of the time your singleton will live as long as your process.
When your process shuts down, OS will reclaim most resources (memory, file handles, sockets...) and it is perfectly normal to allocate that singleton and then just let it die. This would be my recommendation.
It is also a good practice to put Initialize() function for the singleton inside GetInstance() (as pdillon3 demonstrated) instead of having your application explicitly call Initialize(). You didn't specify this part, and if your project is an executable, you should be ok with existing design. But just be careful if you put this code inside a DLL. Some people assume DllMain is a good place to initialize singleton objects and it's not. During DllMain, loader lock global critical section is locked and singleton initializations tend to cause all kinds of trouble.
Plus now instead of 3 methods in your singleton interface, you are down to just one: GetInstance(), nice and simple.
Lastly, as Dietmar mentioned (although I still consider Singleton to be a pattern, not an anti-pattern and GoF agree with me), you should really consider whether or not you actually need a singleton. I use them from time to time, but only when I have no choice, not because they are convenient. They really are a design pattern of last resort when alternative is even more evil. Don't use them just because they are convenient.
Upvotes: 1
Reputation: 547
If you aren't using Visual Studio or C++11, you won't have a unique_ptr<>. In that case, you should stick with boost::scoped_ptr.hpp, since std::auto_ptr will soon be completely deprecated.
#include <boost/scoped_ptr.hpp>
#include <iostream>
class Foo {
Foo() { std::cout << "constructor" << std::endl; }
public:
static Foo& Get() {
static boost::scoped_ptr<Foo> ptr(new Foo);
return *ptr;
}
~Foo() { std::cout << "destructor" << std::endl; }
};
int main() {
Foo& f = Foo::Get();
// f is now valid until the program exits.
//Then it is destroyed before the program finishes exiting.
std::cout << "Work here" << std::endl;
}
Or you can write your own simplified scoped_ptr.
template<typename _T>
class scoped_ptr {
_T* const mPtr;
public:
scoped_ptr(_T* const t) : mPtr(t) {}
~scoped_ptr() { delete mPtr; }
operator _T* () { return const_cast<_T*>(mPtr); }
// add more operators like -> if you want them
};
Upvotes: 1
Reputation: 153830
For a single-threaded application where the singleton isn't accessed after exiting main()
you can use a fairly simple approach which does everything automatically:
Root& Root::get() {
static std::unique_ptr<Root> rc(new Root());
return *rc;
}
The static
in this context means that the variable is initialized the first time the function is called and then stays put. The C++ run-time arranges for the static
variable rc
to be destroyed at some point. For multi-threaded appplications where threads are started before entering main()
you need a different approach which makes sure that the static variable is initialized only by on thread.
That said, please note that I strongly recommend not to employ the anti-pattern Singleton (also known as Global Data). The above code sample doesn't constitute a recommendation of any sort! There are few valid uses where you want to use a singleton, most uses are not. All valid uses I have seen use an immutable Singleton. Mutable singleton objects tend to become a synchronization point and tend to obfuscate the use data as global data does.
Upvotes: 3