I'm encountering a nasty problem in developing an application of mine.
I've got a main executable and some dynamic modules that can be loaded
by it. Both the executable and modules do link to a shared library
called "libbackend.so".
Into libbackend.so, I've put some objects that follow the Singleton
pattern. So I've created a template like this (it uses a Glib::Mutex
object you can easily ignore for thread-safeness):
-------- # code -------
template<typename Instantiated_class>
class Singleton
{
public:
static Instantiated_class& get_instance();
private:
static Instantiated_class* _instance;
static Glib::StaticMutex _mutex;
}; //~ class Singleton
template<typename Instantiated_class>
Instantiated_class*
sgpem::Singleton<Instantiated_class>::_instance = NULL;
template<typename Instantiated_class>
Glib::StaticMutex
sgpem::Singleton<Instantiated_class>::_mutex =
GLIBMM_STATIC_MUTEX_INIT;
template<typename Instantiated_class>
Instantiated_class&
sgpem::Singleton<Instantiated_class>::get_instance()
{
Glib::Mutex::Lock lock(_mutex);
if(_instance == NULL)
_instance = new Instantiated_class();
return *_instance;
}
---- # end code ----
This means that each Singleton I want to have into libbackend.so has
just to do:
-------- # code -------
class SomeClass : public Singleton<SomeClass>
{
friend class Singleton<SomeClass>;
public:
// ...
private:
SomeClass();
SomeClass(const SomeClass&);
}; //~ SomeClass
---- # end code ----
Now, the problem I noticed is that what should be a unique instance of
SomeClass (the one that dwells into libbackend.so) is instantiated
multiple times when the program begins, instead of really the first
time that SomeClass::get_instance() is called.
After investigating this for a little, I discovered that:
$ nm -C .libs/libbackend.so | grep get_instance
0000cd90 W sgpem::Singleton<sgpem::SomeClass>::get_instance()
00010b00 W sgpem::Singleton<sgpem::SomeOtherClass>::get_instance()
$ nm -C .libs/mainexecutable | grep get_instance
08051460 W sgpem::Singleton<sgpem::SomeClass>::get_instance()
08056e70 W sgpem::Singleton<sgpem::SomeOtherClass>::get_instance()
$ nm -C .libs/loadablemodule | grep get_instance
00004cd0 W sgpem::Singleton<sgpem::SomeClass>::get_instance()
00005010 W sgpem::Singleton<sgpem::SomeOtherClass>::get_instance()
So, my guess is that get_instance() of the Singleton template is
inlined and included into both the main executable and each module.
This is why calling SomeClass::get_instance() from one place returns a
SomeClass object, from another place it returns another unrelated
SomeClass object.
I'm not sure how to solve this. Of course, I can drop the template
completely and use the "standard way" to make every class I need a
Singleton, but I rather liked the idea of this approach. :-)
Maybe there's a GCC attribute to prevent inlining for a function,
although I'd prefer to not to use compiler-dependent flags for this.
So, how can i get the symbols for Singleton<SomeClass> to be marked "T"
(global exported symbols into the text section) in libbackend.so and
"U" (undefined) in the main executable and modules?
Thanks for any answer,
Matteo
PS: if I got it wrong, apologies in advance. I'm a student after all,
of course I behave stupidly! :-)
> So, how can i get the symbols for Singleton<SomeClass> to be marked "T"
> (global exported symbols into the text section) in libbackend.so and
> "U" (undefined) in the main executable and modules?
Remove the definition of Singleton<T>::get_instance() from the
body of the class in Singleton.h header, and put it into a separate
Singleton.tc file.
Then '#include "Singleton.tc"' only into the compilation units
where you want the Singleton<SomeClass>::get_instance() to be
defined.
After that, you'll get a 'W' in libbackend.so, and a 'U' everywhere
else, which should be good enough.
Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.