Singleton: Difference between revisions
Content added Content deleted
(→{{header|Kotlin}}: Updated example see https://github.com/dkandalov/rosettacode-kotlin for details) |
(→{{header|C++}}: A proper implementation should only (1) ensure that only one instance exists at any given moment; and (2) provide global access to that instance. Concurrency issues should be considered as a separate matter (in the general case).) |
||
Line 201: | Line 201: | ||
=={{header|C++}}== |
=={{header|C++}}== |
||
A generic singleton template class (implemented via the "Curiously Recurring Template Pattern"[https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern]). Warning: if using a version of C++ prior to C++11, a [[Mutex#C|mutex]] (or similar) is required to access static variables within a multi-threaded program. |
|||
===Thread-safe=== |
|||
'''Operating System:''' Microsoft Windows NT/XP/Vista |
|||
:Uses a [[Win32]] flavor [[Mutex#Win32|Mutex]] - a [[POSIX]] flavor [[Mutex#POSIX|Mutex]] could be used. |
|||
<lang cpp>class Singleton |
|||
{ |
|||
public: |
|||
static Singleton* Instance() |
|||
{ |
|||
// We need to ensure that we don't accidentally create two Singletons |
|||
HANDLE hMutex = CreateMutex(NULL, FALSE, "MySingletonMutex"); |
|||
WaitForSingleObject(hMutex, INFINITE); |
|||
<lang cpp> |
|||
// Create the instance of the class. |
|||
#include <stdexcept> |
|||
// Since it's a static variable, if the class has already been created, |
|||
// It won't be created again. |
|||
static Singleton myInstance; |
|||
template <typename Self> |
|||
// Release our mutex so that other application threads can use this function |
|||
class singleton |
|||
ReleaseMutex( hMutex ); |
|||
{ |
|||
protected: |
|||
static Self* |
|||
sentry; |
|||
public: |
|||
static Self& |
|||
instance() |
|||
{ |
|||
return *sentry; |
|||
} |
|||
singleton() |
|||
{ |
|||
if(sentry) |
|||
throw std::logic_error("Error: attempt to instantiate a singleton over a pre-existing one!"); |
|||
sentry = (Self*)this; |
|||
} |
|||
virtual ~singleton() |
|||
{ |
|||
if(sentry == this) |
|||
sentry = 0; |
|||
} |
|||
}; |
|||
template <typename Self> |
|||
Self* |
|||
singleton<Self>::sentry = 0; |
|||
/* |
|||
// Free the handle |
|||
Example usage: |
|||
CloseHandle( hMutex ); |
|||
*/ |
|||
#include <iostream> |
|||
// Return a pointer to our mutex instance. |
|||
#include <string> |
|||
return &myInstance; |
|||
} |
|||
using namespace |
|||
// Any other public methods |
|||
std; |
|||
class controller : public singleton<controller> |
|||
protected: |
|||
Singleton() |
|||
{ |
|||
// Constructor code goes here. |
|||
} |
|||
~Singleton() |
|||
{ |
|||
// Destructor code goes here. |
|||
} |
|||
// And any other protected methods. |
|||
}</lang> |
|||
===Non-Thread-Safe=== |
|||
This version doesn't require [[Mutex#C|Mutex]], but it is not safe in a multi-threaded environment (before C++11). |
|||
<lang cpp>class Singleton |
|||
{ |
{ |
||
public: |
public: |
||
controller(string const& name) |
|||
static Singleton* Instance() |
|||
: name(name) |
|||
{ |
|||
{ |
|||
// Since it's a static variable, if the class has already been created, |
|||
trace("begin"); |
|||
// It won't be created again. |
|||
} |
|||
static Singleton myInstance; |
|||
~controller() |
|||
{ |
|||
// Return a pointer to our mutex instance. |
|||
trace("end"); |
|||
return &myInstance; |
|||
} |
|||
} |
|||
void |
|||
work() |
|||
// Any other public methods |
|||
{ |
|||
trace("doing stuff"); |
|||
protected: |
|||
} |
|||
Singleton() |
|||
void |
|||
{ |
|||
trace(string const& message) |
|||
// Constructor code goes here. |
|||
{ |
|||
} |
|||
cout << name << ": " << message << endl; |
|||
~Singleton() |
|||
} |
|||
{ |
|||
string |
|||
// Destructor code goes here. |
|||
name; |
|||
} |
|||
}; |
|||
int |
|||
// And any other protected methods. |
|||
main() |
|||
}</lang> |
|||
=== Thread safe (since C++11) === |
|||
This will be thread safe since C++11, where static variables is always thread-safe (according to section 6.7 of The Standard). |
|||
<lang cpp>class Singleton |
|||
{ |
{ |
||
controller* |
|||
public: |
|||
first = new controller("first"); |
|||
static Singleton & Instance() |
|||
controller::instance().work(); |
|||
{ |
|||
delete first; |
|||
// Since it's a static variable, if the class has already been created, |
|||
/* |
|||
// It won't be created again. |
|||
No problem, our first controller no longer exists... |
|||
// And it **is** thread-safe in C++11. |
|||
*/ |
|||
controller |
|||
static Singleton myInstance; |
|||
second("second"); |
|||
controller::instance().work(); |
|||
// Return a reference to our instance. |
|||
try |
|||
return myInstance; |
|||
{ |
|||
} |
|||
/* |
|||
Never happens... |
|||
// delete copy and move constructors and assign operators |
|||
*/ |
|||
Singleton(Singleton const&) = delete; // Copy construct |
|||
controller |
|||
Singleton(Singleton&&) = delete; // Move construct |
|||
goner("goner"); |
|||
Singleton& operator=(Singleton const&) = delete; // Copy assign |
|||
controller::instance().work(); |
|||
Singleton& operator=(Singleton &&) = delete; // Move assign |
|||
} |
|||
catch(exception const& error) |
|||
// Any other public methods |
|||
{ |
|||
cout << error.what() << endl; |
|||
protected: |
|||
} |
|||
Singleton() |
|||
controller::instance().work(); |
|||
{ |
|||
/* |
|||
// Constructor code goes here. |
|||
Never happens (and depending on your system this may or may not print a helpful message!) |
|||
} |
|||
*/ |
|||
controller |
|||
~Singleton() |
|||
goner("goner"); |
|||
{ |
|||
controller::instance().work(); |
|||
// Destructor code goes here. |
|||
} |
|||
} |
|||
</lang> |
|||
// And any other protected methods. |
|||
}</lang> |
|||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |