自定义智能指针类的实现

Ref: https://github.com/SRombauts/shared_ptr
稍作改动。

shared_ptr.h

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <algorithm>

/*
* shared_ptr_count is a container for the allocated pn reference counter.
*/
class shared_ptr_count
{
public:
shared_ptr_count() : pn(nullptr) {}
shared_ptr_count(const shared_ptr_count& count) : pn(count.pn) {}
// swap method for the copy-and-swap idiom (copy constructor and swap method)
void swap(shared_ptr_count& lhs) throw()
{
std::swap(pn, lhs.pn);
}
// getter of the underlying reference counter
long use_count() const throw()
{
long count(0);
if (nullptr != pn)
{
count = *pn;
}
return count;
}
// acquire/share the ownership of the pointer, initializing the reference counter
template <class U>
void acquire(U* p)
{
if (nullptr != p)
{
if (nullptr == pn)
{
try
{
pn = new long(1); // may throw std::bad_alloc
}
catch (std::bad_alloc&)
{
delete p;
throw; // rethrow the std::bad_alloc
}
}
else
{
++(*pn);
}
}
}
// release the ownership of the px pointer, destroying the object when appropriate
template <class U>
void release(U* p)
{
if (nullptr != pn)
{
--(*pn);
if (0 == *pn)
{
delete p;
delete pn;
}
pn = nullptr;
}
}
public:
long* pn; // Reference counter
};
/*
* shared_ptr is a smart pointer retaining ownership of an object throught a provided pointer,
* and sharing this ownership with a reference counter.
* It destroys the object when the last shared pointing to it is destroyed or reset.
*/
template<typename T>
class shared_ptr
{
public:
// The type of the managed object, aliased as member type
typedef T element_type;
// Default constructor
shared_ptr(void) throw() : px(nullptr), pn()
{}
// Constructor with the provided pointer to manage
explicit shared_ptr(T* p) : pn()
{
acquire(p);
}
// Copy constructor (used by the copy-and-swap idiom)
shared_ptr(const shared_ptr& ptr) throw() : pn(ptr.pn)
{
acquire(ptr.px);
}
// Assignment operator using the copy-and-swap idiom (copy constructor and swap method)
shared_ptr& operator=(shared_ptr ptr) throw()
{
swap(ptr);
return *this;
}
// Destructor releases its ownership
inline ~shared_ptr() throw()
{
release();
}
// Reset releases its ownership
inline void reset() throw()
{
release();
}
// Reset release its ownership and re-acquire another one
void reset(T* p)
{
release();
acquire(p);
}
// Swap method for the copy-and-swap idiom
void swap(shared_ptr& lhs) throw()
{
std::swap(px, lhs.px);
pn.swap(lhs.pn);
}
// reference counter operations:
inline operator bool() const throw()
{
return (0 < pn.use_count());
}
inline bool unique() const throw()
{
return (1 == pn.use_count());
}
long use_count() const throw()
{
return pn.use_count();
}
// Underlying pointer operations:
inline T& operator*() const throw()
{
return *px;
}
inline T* operator->() const throw()
{
return px;
}
inline T* get() const throw()
{
return px;
}

private:
// acquire/share the ownership of the px pointer, initializing the reference counter
inline void acquire(T* p)
{
pn.acquire(p); // may throw std::bad_alloc
px = p; // here it is safe to acquire the ownership of the provided raw pointer, where exception cannot be thrown any more
}
// release the ownership of the px pointer, destroying the object when appropriate
inline void release() throw()
{
pn.release(px);
px = nullptr;
}
private:
T* px; // Native pointer
shared_ptr_count pn; // Reference counter
};

// comparasion operators
template<class T, class U> inline bool operator==(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
return (l.get() == r.get());
}
template<class T, class U> inline bool operator!=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
return (l.get() != r.get());
}
template<class T, class U> inline bool operator<=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
return (l.get() <= r.get());
}
template<class T, class U> inline bool operator<(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
return (l.get() < r.get());
}
template<class T, class U> inline bool operator>=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
return (l.get() >= r.get());
}
template<class T, class U> inline bool operator>(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
return (l.get() > r.get());
}

unique_ptr.h

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <algorithm>

template <typename T>
inline T& move(T& v)
{
return v;
}

/*
* unique_ptr is a smart pointer retaining ownership of an object through a provided pointer,
* and sharing this ownership with a reference counter.
* It destroys the object when the last shared pointer pointing to it is destroyed or reset.
*/
template <typename T>
class unique_ptr
{
public:
// The type of the managed object, aliased as member type
typedef T element_type;
// Default constructor
unique_ptr() throw() : px(nullptr)
{}
// Constructor with the provided pointer to manage
explicit unique_ptr(T* p) throw() : px(p)
{}
// Copy constructor (used by the copy-and-swap idiom)
unique_ptr(const unique_ptr& ptr) throw() : px(ptr.px)
{
const_cast<unique_ptr&>(ptr).px = nullptr; // const-cast to force ownership transfer.
}
// Assignment operator using the copy-and-swap idiom
unique_ptr& operator=(unique_ptr ptr) throw()
{
swap(ptr);
return *this;
}
// Destructor releases its ownership and destroy the object
inline ~unique_ptr() throw()
{
destroy();
}
// Reset releases its ownership and destroy the object
inline void reset() throw()
{
destroy();
}
// Reset release its ownership and re-acquire another one
void reset(T* p) throw()
{
destroy();
px = p;
}
// Swap method for the copy-and-swap idiom
void swap(unique_ptr& lhs) throw()
{
std::swap(px, lhs.px);
}
// Release the ownership of the px pointer without destroying the object
inline void release() throw()
{
px = nullptr;
}

// reference counter operations:
inline operator bool() const throw()
{
return (nullptr != px);
}

// underlying pointer operations:
inline T& operator*() const throw()
{
return *px;
}
inline T* operator->() const throw()
{
return px;
}
inline T* get() const throw()
{
return px;
}

private:
// release the ownership of the px pointer and destroy the object
inline void destroy() throw()
{
delete px;
px = nullptr;
}

private:
T* px; // Native pointer
};

// comparaison operators
template<class T, class U> inline bool operator==(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
return (l.get() == r.get());
}
template<class T, class U> inline bool operator!=(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
return (l.get() != r.get());
}
template<class T, class U> inline bool operator<=(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
return (l.get() <= r.get());
}
template<class T, class U> inline bool operator<(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
return (l.get() < r.get());
}
template<class T, class U> inline bool operator>=(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
return (l.get() >= r.get());
}
template<class T, class U> inline bool operator>(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
return (l.get() > r.get());
}

test

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
#include <iostream>
#include <vector>
#include <string>
using std::string;
using std::vector;
using std::cout;
using std::endl;

#include "shared_ptr.h"
#include "unique_ptr.h"

// shared_ptr usage
void shared_ptr_test()
{

std::cout << "shared_ptr_test: in\n";
// two shared pointers representing two persons by their name
shared_ptr<string> pNico(new string("nico"));
shared_ptr<string> pJutta(new string("jutta"));
// capitalize person names
(*pNico)[0] = 'N';
pJutta->replace(0, 1, "J");
// put them multiple times in a container
vector<shared_ptr<string>> whoMadeCoffee;
whoMadeCoffee.push_back(pJutta);
whoMadeCoffee.push_back(pJutta);
whoMadeCoffee.push_back(pNico);
whoMadeCoffee.push_back(pJutta);
whoMadeCoffee.push_back(pNico);
// print all elements
for (auto ptr : whoMadeCoffee)
{
cout << *ptr << " ";
}
cout << endl;
// overwrite a name again
*pNico = "Nicolai";
// print all elements again
for (auto ptr : whoMadeCoffee)
{
cout << *ptr << " ";
}
cout << endl;
// print some internal data
cout << "use_count: " << whoMadeCoffee[0].use_count() << endl;
std::cout << "shared_ptr_test: out\n";
}

// unique_ptr usage
void unique_ptr_test()
{

std::cout << "unique_ptr_test: in\n";
// create and initialize (pointer to) string:
unique_ptr<string> up(new string("nico"));
(*up)[0] = 'N'; // replace first character
up->append("lai"); // append some characters
cout << *up << std::endl; // print whole string
unique_ptr<string> up2(move(up));
cout << *up2 << std::endl; // print whole string
if (up.get() == nullptr)
{
cout << "up is empty" << endl;
}
std::cout << "unique_ptr_test: out\n";
}

// main
int main()
{

shared_ptr_test();
unique_ptr_test();
system("Pause");
}