In dll A I have a template singleton:
template <class T>
class Singleton
{
public:
static T &instance()
{
static T _instance;
return _instance;
}
private:
//All constructors are here
};
In Dll B I define a class Logger. Dlls C,D and E use the Logger and it is accessed like this:
Singleton<Logger>::instance();
The problem is that each dll instantiates its own copy of
Singleton<Logger>.
instead of using the same singleton instance. I understand that the solution to this problem is using extern templates. That is dlls C,D and E have to include
extern template class Singleton<Logger>;
and dll B must include:
template class Singleton<Logger>;
This still cause more than one template instance to be created. I tried putting the extern in all the dlls and it still didn't work I tried removing the extern from all the dlls and it still didn't work. Is this not the standard way to implement template singletons? What is the correct way to do this?
The trick that works for me is to add __declspec(dllexport)
to the singleton's template definition; split the template implementation from the class definition and only include the implementation in the A DLL; and finally, force the template to be instantiated in the A DLL by creating a dummy function that calls Singleton<Logger>::instance()
.
So in your A DLL's header file, you define the Singleton template like this:
template <class T>
class __declspec(dllexport) Singleton {
public:
static T &instance();
};
Then in your A DLL's cpp file you define the template implementation, and force an instantiation of Singleton<Logger>
like this:
template <class T>
T &Singleton<T>::instance() {
static T _instance;
return _instance;
};
void instantiate_logger() {
Singleton<Logger>::instance();
}
With my compiler at least, I don't need to call instantiate_logger
from anywhere. Just having it exist forces the code to be generated. So if you dump the A DLL's export table at this point, you should see an entry for Singleton<Logger>::instance()
.
Now in your C DLL and D DLL, you can include the header file with the template definition for Singleton
, but because there is no template implementation, the compiler won't be able to create any code for that template. This means the linker will end up complaining about unresolved externals for Singleton<Logger>::instance()
, but you just have to link in the A DLL's export library to fix that.
The bottom line is that the code for Singleton<Logger>::instance()
is only ever implemented in DLL A, so you can never have more than one instance.
The "correct" way to do this is...not to use a singleton.
If you want all other code to use the same instance of some type, then give that code a reference to that instance - as a parameter to a function or a constructor.
Using a singleton (non-template) would be exactly the same as using a global variable, a practice you should avoid.
Using a template means the compiler decides how to instantiate the code, and how to access the "instance". The problem you're experiencing is a combination of this and using a static in a DLL.
There are many reasons why singletons are bad, including lifetime issues (when, exactly, would it be safe to delete a singleton?), thread-safety issues, global shared access issues and more.
In summary, if you only want one instance of a thing, only create one instance of it, and pass it around to code that needs it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With