diff --git a/include/loki/Singleton.h b/include/loki/Singleton.h index 00bdd9e..e5ca7b9 100644 --- a/include/loki/Singleton.h +++ b/include/loki/Singleton.h @@ -71,7 +71,7 @@ namespace Loki template struct Deleter { - typedef void (*Type)(T*); + typedef void (*Type)(T*); static void Delete(T* pObj) { delete pObj; } }; @@ -138,13 +138,13 @@ namespace Loki std::atexit(Private::AtExitFn); } - template + template void SetLongevity(T* pDynObject, unsigned int longevity, - typename Private::Deleter::Type d = Private::Deleter::Delete) + typename Private::Deleter::Type d = Private::Deleter::Delete) { - SetLongevity::Type>(pDynObject, longevity, d); - } - + SetLongevity::Type>(pDynObject, longevity, d); + } + //////////////////////////////////////////////////////////////////////////////// // class template CreateUsingNew // Implementation of the CreationPolicy used by SingletonHolder @@ -194,7 +194,7 @@ namespace Loki template struct CreateStatic { - + #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4121 ) @@ -283,7 +283,76 @@ namespace Loki #ifndef ATEXIT_FIXED template bool PhoenixSingleton::destroyedOnce_ = false; #endif + +//////////////////////////////////////////////////////////////////////////////// +// class template DeletableSingleton +// Copyright (c) 2004 by Curtis Krauskopf - curtis@decompile.com +// +// A DeletableSingleton allows the instantiated singleton to be +// destroyed at any time. The singleton can be reinstantiated at +// any time, even during program termination. +// If the singleton exists when the program terminates, it will +// be automatically deleted. +// +// The singleton can be deleted manually: +// DeletableSingleton::GracefulDelete(); +//////////////////////////////////////////////////////////////////////////////// + template + class DeletableSingleton + { + public: + + static void ScheduleDestruction(T*, atexit_pfn_t pFun) + { + static bool firstPass = true; + isDead = false; + deleter = pFun; + if (firstPass || needCallback) + { + std::atexit(atexitCallback); + firstPass = false; + needCallback = false; + } + } + + static void OnDeadReference() + { + } + + static void GracefulDelete() + { + if (isDead) + return; + isDead = true; + deleter(); + } + + protected: + static atexit_pfn_t deleter; + static bool isDead; + static bool needCallback; + + static void atexitCallback() + { +#ifdef ATEXIT_FIXED + needCallback = true; +#else + needCallback = false; +#endif + GracefulDelete(); + } + }; + + template + atexit_pfn_t DeletableSingleton::deleter = 0; + + template + bool DeletableSingleton::isDead = true; + + template + bool DeletableSingleton::needCallback = true; + //////////////////////////////////////////////////////////////////////////////// // class template Adapter // Helper for SingletonWithLongevity below @@ -435,7 +504,7 @@ namespace Loki { if (destroyed_) { - destroyed_ = false; + destroyed_ = false; LifetimePolicy::OnDeadReference(); } pInstance_ = CreationPolicy::Create(); diff --git a/test/Makefile b/test/Makefile index 0012ef4..cc19b6a 100755 --- a/test/Makefile +++ b/test/Makefile @@ -8,6 +8,7 @@ SUBTARGETS = \ sub-OrderedStatic \ sub-RegressionTest \ sub-SafeFormat \ + sub-Singleton \ sub-SmallObj all: $(SUBTARGETS) @@ -32,6 +33,12 @@ sub-SafeFormat: FORCE $(MAKE) -f $(MAKEFILE) @cd .. +sub-Singleton: FORCE + cd Singleton && \ + $(MAKE) -f $(MAKEFILE)-DeletableSingleton && \ + $(MAKE) -f $(MAKEFILE)-Phoenix + @cd .. + sub-SmallObj: FORCE cd SmallObj && \ $(MAKE) -f $(MAKEFILE) diff --git a/test/Singleton/DeletableSingleton.cpp b/test/Singleton/DeletableSingleton.cpp new file mode 100755 index 0000000..2ce1260 --- /dev/null +++ b/test/Singleton/DeletableSingleton.cpp @@ -0,0 +1,80 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2005 by Curtis Krauskopf +// Copyright (c) 2005 by Peter Kuemmel +// +// Code covered by the MIT License +// The authors make no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +// Show an example of a Loki policy that uses DeletableSingleton. +// +// Expected output: +// +// Log::Log() +// Log singleton instantiated +// Going to manually delete log. +// Log::~Log() +// Log::Log() +// Log reinstantiated. +// Going to terminate program now. +// Log::~Log() +// + +#include +#include "loki/Singleton.h" // for Loki::SingletonHolder + +using namespace std; // okay for small programs +using namespace Loki; // okay for small programs + +// A singleton Log object derived from the Example class. +// Its longevity is set by the user on the command line. +// +class Log +{ +public: + Log() + { + print("Log::Log()"); + }; + ~Log() + { + print("Log::~Log()"); + } + void print(const char *s) + { + cout << s << endl; + } +}; + +typedef SingletonHolder log; + +class Example +{ +public: + void method() + { + cout << "test\n"; + } +}; + + +int main(int argc, char *argv[]) +{ + // Instantiate both singletons by calling them... + log::Instance().print("Log singleton instantiated"); + log::Instance().print("Going to manually delete log."); + + DeletableSingleton::GracefulDelete(); + + log::Instance().print("Log reinstantiated."); + log::Instance().print("Going to terminate program now."); + +#if defined(__BORLANDC__) || defined(__GNUC__) || defined(_MSC_VER) + system("pause"); // Stop console window from closing if run from IDE. +#endif + + return 0; +} + diff --git a/test/Singleton/Makefile-DeletableSingleton b/test/Singleton/Makefile-DeletableSingleton new file mode 100755 index 0000000..ad24a75 --- /dev/null +++ b/test/Singleton/Makefile-DeletableSingleton @@ -0,0 +1,32 @@ + + +CPP = g++ +CC = gcc +OBJ = DeletableSingleton.o +LINKOBJ = DeletableSingleton.o +CXXINCS = -I./../../include +LIBS = -L../../lib -lloki +CXXFLAGS = $(CXXINCS) -O2 -DNDEBUG +BIN = DeletableSingleton-gcc.exe +RM = rm -f +CHK_DIR_EXISTS= if not exist +MKDIR = mkdir + +.PHONY: all all-before all-after clean clean-custom + +all: all-before $(BIN) all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +$(BIN): $(OBJ) + $(CPP) $(LINKOBJ) -o DeletableSingleton-gcc.exe $(LIBS) + +check_tmp: + @$(CHK_DIR_EXISTS) "" $(MKDIR) "tmp" + +Factory.o: Factory.cpp + $(CPP) -c DeletableSingleton.cpp -o DeletableSingleton.o $(CXXFLAGS) + + diff --git a/test/Singleton/Makefile-Phoenix b/test/Singleton/Makefile-Phoenix new file mode 100755 index 0000000..47c19fb --- /dev/null +++ b/test/Singleton/Makefile-Phoenix @@ -0,0 +1,32 @@ + + +CPP = g++ +CC = gcc +OBJ = Phoenix.o +LINKOBJ = Phoenix.o +CXXINCS = -I./../../include +LIBS = -L../../lib -lloki +CXXFLAGS = $(CXXINCS) -O2 -DNDEBUG +BIN = Phoenix-gcc.exe +RM = rm -f +CHK_DIR_EXISTS= if not exist +MKDIR = mkdir + +.PHONY: all all-before all-after clean clean-custom + +all: all-before $(BIN) all-after + + +clean: clean-custom + ${RM} $(OBJ) $(BIN) + +$(BIN): $(OBJ) + $(CPP) $(LINKOBJ) -o Phoenix-gcc.exe $(LIBS) + +check_tmp: + @$(CHK_DIR_EXISTS) "" $(MKDIR) "tmp" + +Factory.o: Factory.cpp + $(CPP) -c Phoenix.cpp -o Phoenix.o $(CXXFLAGS) + + diff --git a/test/Singleton/Phoenix.cpp b/test/Singleton/Phoenix.cpp new file mode 100755 index 0000000..acc579c --- /dev/null +++ b/test/Singleton/Phoenix.cpp @@ -0,0 +1,91 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2005 by Curtis Krauskopf +// Copyright (c) 2005 by Peter Kuemmel +// +// Code covered by the MIT License +// The authors make no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +// A singleton Log object that resurrects itself after +// it has been automatically destroyed during program +// termination. When a dead-reference to the Log +// singleton is detected, it is resurrected automatically. +// +// Expected output: +// Example c'tor +// Log c'tor +// Log now instantiated. +// Log d'tor +// Example d'tor starting +// Log c'tor +// Log: inside Example d'tor +// Example d'tor finished +// +// The last line of the output only appears when this +// program is compiled with the ATEXIT_FIXED symbol +// defined (see the Loki library and the CUJ article). +// + +#include +#include "loki/Singleton.h" // for Loki::SingletonHolder + +using namespace std; // okay for small programs +using namespace Loki; // okay for small programs + +class Log +{ +public: + Log() + { + echo("Log c'tor"); + } + ~Log() + { + echo("Log d'tor"); + } + void echo(const char *s) + { + cout << s << endl; + } +}; + +typedef SingletonHolder log; + + +// A generic example class that stores and echoes a const char. +// +class Example +{ +public: + Example() + { + echo("Example c'tor"); + } + ~Example() + { + echo("Example d'tor starting"); + log::Instance().echo("Log: inside Example d'tor"); + echo("Example d'tor finished"); + } + void echo(const char *s) + { + cout << s << endl; + } +}; + + +int main(int argc, char* argv[]) +{ + Example *example = new Example(); + SetLongevity(example, 1, &Loki::Private::Deleter::Delete); + log::Instance().echo("Log now instantiated."); + +#if defined(__BORLANDC__) || defined(__GNUC__) || defined(_MSC_VER) + system("pause"); // Stop console window from closing if run from IDE. +#endif + + return 0; +} + diff --git a/test/Singleton/make.msvc.bat b/test/Singleton/make.msvc.bat new file mode 100755 index 0000000..4e2e64f --- /dev/null +++ b/test/Singleton/make.msvc.bat @@ -0,0 +1,31 @@ +if not exist tmp\ mkdir tmp + + +:: DeletableSingleton.cpp + +cl -c -Zm200 -O2 -DNDEBUG -MT -EHsc -GR -W0 -wd4710 -I"." -I"..\..\include" -Fotmp\ DeletableSingleton.cpp + +if not defined LOKI_MSVC_NOLIB ( + +link /NOLOGO /SUBSYSTEM:CONSOLE /incremental:no /OUT:"DeletableSingleton-msvc.exe" ..\..\lib\loki.lib tmp\DeletableSingleton.obj + +) else ( + +link /NOLOGO /SUBSYSTEM:CONSOLE /incremental:no /OUT:"DeletableSingleton-msvc.exe" tmp\DeletableSingleton.obj ..\..\lib\SmallObj.obj ..\..\lib\Singleton.obj + +) + + +:: Phoenix.cpp + +cl -c -Zm200 -O2 -DNDEBUG -MT -EHsc -GR -W0 -wd4710 -I"." -I"..\..\include" -Fotmp\ Phoenix.cpp + +if not defined LOKI_MSVC_NOLIB ( + +link /NOLOGO /SUBSYSTEM:CONSOLE /incremental:no /OUT:"Phoenix-msvc.exe" ..\..\lib\loki.lib tmp\Phoenix.obj + +) else ( + +link /NOLOGO /SUBSYSTEM:CONSOLE /incremental:no /OUT:"Phoenix-msvc.exe" tmp\Phoenix.obj ..\..\lib\SmallObj.obj ..\..\lib\Singleton.obj + +) diff --git a/test/make.msvc.bat b/test/make.msvc.bat index 91dc7b5..91af7d3 100755 --- a/test/make.msvc.bat +++ b/test/make.msvc.bat @@ -23,6 +23,10 @@ cd SafeFormat call make.msvc.bat cd .. +cd Singleton +call make.msvc.bat +cd .. + cd SmallObj call make.msvc.bat cd ..