The following small example implements a singleton pattern that I've seen many times:
#include <iostream>
class SingletonTest {
private:
SingletonTest() {}
static SingletonTest *instance;
~SingletonTest() {
std::cout << "Destructing!!" << std::endl;
}
public:
static SingletonTest *get_instance开发者_运维问答() {
if(!instance) instance = new SingletonTest;
return instance;
}
};
SingletonTest *SingletonTest::instance = 0;
int main(int argc, char *argv[]) {
SingletonTest *s = SingletonTest::get_instance();
return 0;
}
The main problem I have with this is that the destructor of my singleton is never called.
I can instead make instance
a (c++0x?) shared_ptr
, which works well - except that it means my destructor has to be public.
I could add a static 'cleanup' method but that opens up the possibility of user error (i.e. forgetting to call it). It would also not allow for proper cleanup in the face of (unhandled) exceptions.
Is there a common strategy/pattern that will allow lazy instantiation, 'automatically' call my destructor, and still allow me to keep the destructor private?
...not exactly a direct answer, but too long for a comment - why not do the singleton this way:
class SingletonTest {
private:
SingletonTest() {}
~SingletonTest() {
std::cout << "Destructing!!" << std::endl;
}
public:
static SingletonTest& get_instance() {
static SingletonTest instance;
return instance;
}
};
Now you have a lazy singleton that will be destructed on exit... It's not any less re-entrant than your code...
You could write a deinitialization function and call atexit()
inside the object constructor to register it. Then when C++ runtime deinitializes the module it will at some point after main() call your deinitialization function. That bold italic is there because you get rather loose control on when exactly it is called and that can lead to deinitialization order fiasco - be careful.
You could always friend the shared_ptr (or rather scoped_ptr, which is more fitting) to allow it access to your private destructor.
Note that there's also the system atexit()
function which can register a function to call at the end of the application. You could pass a static function of your singleton that just does delete instanance;
to it.
Note that it's usually a good idea separates the class that is to be a singleton from the singleton-ness of it. Especially for testing and/or when you do need the doubleton. :)
While I'm at it, try to avoid lazy initialization. Initialize/create your singletons at startup, in a well determined order. This allows them to shut down properly and resolves dependencies without surprises. (I have had cyclic singleton hell... it's easier than you think...)
You can use a private destructor with shared_ptr
by passing in a deleter that has access to the destructor (such as a class defined as a member of SingletonTest
).
However, you need to be very careful when destroying singletons to ensure that they are not used after they are destroyed. Why not just use a plain global variable anyway?
if you declare the class which does the actual delete
op as a friend (let it be shared_ptr<SingletonTest>
or some kind of default deleter) a friend, your destructor can be private.
Although i dont see any necessarity for making it private.
The first question is: do you want the singleton to be destructed. Destructing a singleton can lead to order of destruction problems; and since you're shutting down, the destructor can't be necessary to maintain program invariants. About the only time you want to run the destructor of a singleton is if it manages resources that the system won't automatically clean up, like temporary files. Otherwise, it's better policy to not call the destructor on it.
Given that, if you want the destructor to be called, there are two
alternatives: declare the single object as a static local variable in
the instance
function, or use std::auto_ptr
or something similar,
instead of a raw pointer, as the pointer to it.
精彩评论