-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathsingletonCRTP.cpp
More file actions
82 lines (69 loc) · 2.56 KB
/
singletonCRTP.cpp
File metadata and controls
82 lines (69 loc) · 2.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Singleton pattern via CRTP (curiously recurring template pattern)
// thread safe in C++11 and later
#include <iostream>
#include <type_traits>
// generic Singleton
template <typename T>
class Singleton {
protected:
Singleton(const Singleton&) = delete; // to prevent CASE 3
Singleton& operator=(const Singleton&) = delete; // to prevent CASE 4
Singleton() noexcept = default; // to allow creation of Singleton<Foo>
// by the derived class Foo, since otherwise the (deleted)
// copy constructor prevents the compiler from generating
// a default constructor;
// declared protected to prevent CASE 5
public:
static T& get_instance() noexcept(std::is_nothrow_constructible<T>::value) {
static T instance;
return instance;
}
// thread local instance
static thread_local T& get_thread_local_instance() noexcept(
std::is_nothrow_constructible<T>::value) {
static T instance;
return instance;
}
};
// specific Singleton instance
// use const if you want a const instance returned
// make the constructor and destructor private
class Foo : public Singleton</*const*/ Foo> {
// so Singleton<Foo> can access the constructor and destructor of Foo
friend class Singleton<Foo>;
Foo() // to prevent CASE 1
{
std::cout << "Foo::Foo() private constructor\n";
}
// OK to be private, since Singleton<Foo> is a friend and can invoke it
~Foo() // to prevent CASE 2
{
std::cout << "Foo::~Foo() private destructor\n";
}
public:
void say_hello() { std::cout << "\t Hello from Singleton\n"; }
};
int main() {
Foo& sFoo = Foo::get_instance();
sFoo.say_hello();
Foo& sAnotherFoo = Foo::get_instance(); // OK, get the same instance
sAnotherFoo.say_hello();
Foo& sYetAnotherFoo = sFoo; // still OK, get the same instance
sYetAnotherFoo.say_hello();
thread_local Foo& stlFoo =
Foo::get_thread_local_instance(); // thread local instance
stlFoo.say_hello();
// CASE 1: error: 'Foo::Foo()' is private
// Foo foo;
// Foo* psFoo = new Foo;
// CASE 2: error: 'Foo::~Foo()' is private
Foo* psFoo = &Foo::get_instance(); // can get pointer
psFoo->say_hello();
// delete psFoo; // cannot delete it
// CASE 3: error: use of deleted function 'Foo::Foo(const Foo&)'
// Foo foo(sFoo);
// CASE 4: error: use of deleted function 'Foo& Foo::operator=(const Foo&)'
// sFoo = sAnotherFoo;
// CASE 5: error: 'Singleton<T>::Singleton() [with T = Foo]' is protected
// Singleton<Foo> direct_sFoo;
}