summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWillem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>2016-05-17 11:22:17 +0200
committerWillem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>2016-05-17 11:45:28 +0200
commit73ad6a97531b6bc1d311eceb6ba2770fdf407b81 (patch)
tree94430d9945144b97e61e47d6f5424c2e777f556a
parentd60df8bbd0e17016036c279720d6e3464a4d295c (diff)
Avoid defining singleton construction in header file
That way, the call to new is always executed by code inside libastra. This avoids the situation where a singleton gets created by a copy of the constructor linked into an object file outside of libastra, such as a .mex file, which would then also cause the vtable to be outside of libastra. This situation would cause issues when .mex files are unloaded.
-rw-r--r--include/astra/Singleton.h22
1 files changed, 18 insertions, 4 deletions
diff --git a/include/astra/Singleton.h b/include/astra/Singleton.h
index a256187..1ef4bba 100644
--- a/include/astra/Singleton.h
+++ b/include/astra/Singleton.h
@@ -57,15 +57,17 @@ class Singleton {
m_singleton = 0;
}
+ static void construct();
+
// get singleton
static T& getSingleton() {
if (!m_singleton)
- m_singleton = new T();
+ construct();
return *m_singleton;
}
static T* getSingletonPtr() {
if (!m_singleton)
- m_singleton = new T();
+ construct();
return m_singleton;
}
@@ -76,11 +78,23 @@ class Singleton {
};
-#define DEFINE_SINGLETON(T) template<> T* Singleton<T >::m_singleton = 0
+// We specifically avoid defining construct() in the header.
+// That way, the call to new is always executed by code inside libastra.
+// This avoids the situation where a singleton gets created by a copy
+// of the constructor linked into an object file outside of libastra, such
+// as a .mex file, which would then also cause the vtable to be outside of
+// libastra. This situation would cause issues when .mex files are unloaded.
+
+#define DEFINE_SINGLETON(T) \
+template<> void Singleton<T >::construct() { m_singleton = new T(); } \
+template<> T* Singleton<T >::m_singleton = 0
+
// This is a hack to support statements like
// DEFINE_SINGLETON2(CTemplatedClass<C1, C2>);
-#define DEFINE_SINGLETON2(A,B) template<> A,B* Singleton<A,B >::m_singleton = 0
+#define DEFINE_SINGLETON2(A,B) \
+template<> void Singleton<A,B >::construct() { m_singleton = new A,B(); } \
+template<> A,B* Singleton<A,B >::m_singleton = 0
} // end namespace