From 73ad6a97531b6bc1d311eceb6ba2770fdf407b81 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Tue, 17 May 2016 11:22:17 +0200 Subject: 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. --- include/astra/Singleton.h | 22 ++++++++++++++++++---- 1 file 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::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::construct() { m_singleton = new T(); } \ +template<> T* Singleton::m_singleton = 0 + // This is a hack to support statements like // DEFINE_SINGLETON2(CTemplatedClass); -#define DEFINE_SINGLETON2(A,B) template<> A,B* Singleton::m_singleton = 0 +#define DEFINE_SINGLETON2(A,B) \ +template<> void Singleton::construct() { m_singleton = new A,B(); } \ +template<> A,B* Singleton::m_singleton = 0 } // end namespace -- cgit v1.2.3 From f9b68bafd90941d9faf53e5e2771361e3ab4336a Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Tue, 17 May 2016 16:00:28 +0200 Subject: Add sanity check --- include/astra/Singleton.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/astra/Singleton.h b/include/astra/Singleton.h index 1ef4bba..784c521 100644 --- a/include/astra/Singleton.h +++ b/include/astra/Singleton.h @@ -86,14 +86,14 @@ class Singleton { // libastra. This situation would cause issues when .mex files are unloaded. #define DEFINE_SINGLETON(T) \ -template<> void Singleton::construct() { m_singleton = new T(); } \ +template<> void Singleton::construct() { assert(!m_singleton); m_singleton = new T(); } \ template<> T* Singleton::m_singleton = 0 // This is a hack to support statements like // DEFINE_SINGLETON2(CTemplatedClass); #define DEFINE_SINGLETON2(A,B) \ -template<> void Singleton::construct() { m_singleton = new A,B(); } \ +template<> void Singleton::construct() { assert(!m_singleton); m_singleton = new A,B(); } \ template<> A,B* Singleton::m_singleton = 0 } // end namespace -- cgit v1.2.3