1
#ifndef _STL_COLLECTION_H
2
#define _STL_COLLECTION_H
3
4
#include <memory>
5
#include <vector>
6
#include <loki/Threads.h>
7
8
/**
9
@class STLCollection
10
@brief 基于STL容器(vector,list,deque)實現的數據結構通用集合類
11
12
* 提供以索引作為外參的以下公共通用接口
13
* add --- 向前或向后增加單個元素
14
* insert --- 插入單個元素
15
* erase --- 刪除單個或多個元素
16
* set --- 修改某個元素
17
* get --- 獲取某個元素
18
* find --- 查找某個元素
19
* front --- 獲取第一個元素
20
* back --- 獲取最后一個元素
21
*/
22
23
template<typename T,
24
template <class, class> class ThreadModel = LOKI_DEFAULT_THREADING,
25
class MutexPolicy = LOKI_DEFAULT_MUTEX,
26
template<class T,class U > class C = std::vector,
27
template <class T> class U = std::allocator
28
>
29
class STLCollection : public C<T,U<T> >
30
{
31
typedef U<T> Allocator;
32
typedef C<T,Allocator> base;
33
typedef STLCollection<T,ThreadModel,MutexPolicy,C,U> self;
34
35
public:
36
STLCollection()
37
{
38
}
39
explicit STLCollection(const Allocator& al)
40
:base(al)
41
{
42
}
43
explicit STLCollection(size_t n)
44
:base(n)
45
{
46
}
47
STLCollection(size_t n,const T& t)
48
:base(n,t)
49
{
50
}
51
STLCollection(size_t n,const T& t,const Allocator& al)
52
:base(n,t,al)
53
{
54
}
55
STLCollection(const STLCollection& right)
56
:base(right)
57
{
58
}
59
60
template<class InputIterator>
61
STLCollection(InputIterator first,InputIterator last)
62
:base(first,last)
63
{
64
}
65
66
template<class InputIterator>
67
STLCollection(InputIterator first,InputIterator last,const Allocator& al)
68
:base(first,last,al)
69
{
70
}
71
~STLCollection()
72
{
73
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
74
}
75
76
public:
77
using base::erase;
78
using base::insert;
79
using base::front;
80
using base::back;
81
82
void add(const T& t,bool append = true)
83
{
84
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
85
if (append)
86
base::insert(base::end(),t);
87
else
88
base::insert(base::begin(),t);
89
}
90
void insert(size_t index,const T& t)
91
{
92
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
93
insert_impl(index,t,typename std::iterator_traits<typename base::iterator>::iterator_category());
94
}
95
96
void erase(size_t index)
97
{
98
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
99
erase_impl(index,typename std::iterator_traits<typename base::iterator>::iterator_category());
100
}
101
void erase(size_t beg,size_t end)
102
{
103
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
104
erase_impl(beg,end,typename std::iterator_traits<typename base::iterator>::iterator_category());
105
}
106
void erase(const T& val)
107
{
108
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
109
typename base::iterator it = std::find(base::begin(),base::end(),val);
110
if (it != base::end()) base::erase(it);
111
}
112
template<class Predicate>
113
void erase(const Predicate& Pred)
114
{
115
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
116
typename base::iterator it = std::find_if(base::begin(),base::end(),Pred);
117
if (it != base::end()) base::erase(it);
118
}
119
120
void set(size_t index,const T& t)
121
{
122
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
123
T* p = get(index);
124
if (p) *p = t;
125
}
126
127
T* get(size_t index)
128
{
129
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
130
return get_impl(index,typename std::iterator_traits<typename base::iterator>::iterator_category());
131
}
132
const T* get(size_t index) const
133
{
134
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
135
return get_impl(index,typename std::iterator_traits<typename base::iterator>::iterator_category());
136
}
137
138
T* find(const T& val,size_t* index)
139
{
140
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
141
142
typename base::iterator it = std::find(base::begin(),base::end(),val);
143
if (it == base::end()) return NULL;
144
if (index) *index = std::distance(base::begin(),it);
145
return ⁢
146
}
147
const T* find(const T& val,size_t* index) const
148
{
149
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
150
151
typename base::const_iterator it = std::find(base::begin(),base::end(),val);
152
if (it == base::end()) return NULL;
153
if (index) *index = std::distance(base::begin(),it);
154
return ⁢
155
}
156
template<class Predicate>
157
T* find(const Predicate& Pred,size_t* index)
158
{
159
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
160
161
typename base::iterator it = std::find_if(base::begin(),base::end(),Pred);
162
if (it == base::end()) return NULL;
163
if (index) *index = std::distance(base::begin(),it);
164
return ⁢
165
}
166
template<class Predicate>
167
const T* find(const Predicate& Pred,size_t* index) const
168
{
169
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
170
171
typename base::const_iterator it = std::find_if(base::begin(),base::end(),Pred);
172
if (it == base::end()) return NULL;
173
if (index) *index = std::distance(base::begin(),it);
174
return ⁢
175
}
176
177
T* front()
178
{
179
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
180
181
if (base::empty()) return NULL;
182
return &base::front();
183
}
184
const T* front() const
185
{
186
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
187
188
if (base::empty()) return NULL;
189
return &base::front();
190
}
191
192
T* back()
193
{
194
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
195
196
if (base::empty()) return NULL;
197
return &base::back();
198
}
199
const T* back() const
200
{
201
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
202
203
if (base::empty()) return NULL;
204
return &base::back();
205
}
206
207
bool is_empty() const
208
{
209
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
210
return base::empty();
211
}
212
213
private:
214
void insert_impl(size_t index,const T& t,std::random_access_iterator_tag tag)
215
{
216
if (index < base::size())
217
{
218
base::insert(base::begin()+index,t);
219
}
220
}
221
void insert_impl(size_t index,const T& t,std::input_iterator_tag tag)
222
{
223
if (index < base::size())
224
{
225
typename base::iterator it = base::begin();
226
while(index--) ++it;
227
base::insert(it,t);
228
}
229
}
230
void erase_impl(size_t index,std::random_access_iterator_tag tag)
231
{
232
if (index < base::size())
233
{
234
base::erase(base::begin()+index);
235
}
236
}
237
void erase_impl(size_t index,std::input_iterator_tag tag)
238
{
239
if (index < base::size())
240
{
241
typename base::iterator it = base::begin();
242
while(index--) ++it;
243
base::erase(it);
244
}
245
}
246
void erase_impl(size_t beg,size_t end,std::random_access_iterator_tag tag)
247
{
248
end = std::min(end,base::size());
249
if (beg < end)
250
{
251
base::erase(base::begin()+beg,base::begin()+end);
252
}
253
}
254
void erase_impl(size_t beg,size_t end,std::input_iterator_tag tag)
255
{
256
end = std::min(end,base::size());
257
if (beg < end)
258
{
259
typename base::iterator it = base::begin();
260
while(beg++ < end) it = base::erase(it);
261
}
262
}
263
T* get_impl(size_t index,std::random_access_iterator_tag tag)
264
{
265
if (index>=base::size())
266
return NULL;
267
return &(*(base::begin()+index));
268
}
269
const T* get_impl(size_t index,std::random_access_iterator_tag tag) const
270
{
271
if (index>=base::size())
272
return NULL;
273
return &(*(base::begin()+index));
274
}
275
T* get_impl(size_t index,std::input_iterator_tag tag)
276
{
277
if (index>=base::size())
278
return NULL;
279
typename base::iterator it = base::begin();
280
while (index--) ++it;
281
return &(*it);
282
}
283
const T* get_impl(size_t index,std::input_iterator_tag tag) const
284
{
285
if (index>=base::size())
286
return NULL;
287
typename base::const_iterator it = base::begin();
288
while(index--) ++it;
289
return &(*it);
290
}
291
private:
292
ThreadModel<STLCollection,MutexPolicy> lock_;
293
};
294
295
#endif

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

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

現在來看一下它的應用,一個網絡通訊項目,由UI客戶端(gsoap & c++開發)和服務端(java開發)構成,服務端已實現了一些web service的同步方法,客戶端需要調用它實現相關功能,為了不阻塞界面,因此需要轉化成異步方式調用,調用的結果使用PostMessage API 發自定義消息給窗口,因此發送消息方new 了一個結果的拷貝給窗口,窗口收到后再delete這個結果,但有個問題是post消息可能會丟失導致結果得不到釋放,產生內存泄露。因此設計一個智能指針容器而且是線程安全的,在發消息時將結果拷貝加到容器中,在接收方處理結果后再從容器中刪除它,這樣就可保證無內存泄露問題了。關于智能指針容器,boost中有ptr_vector,ptr_list,ptr_set等現成的,但是它們不是按照指針本身而是指針指向的對象來對待的,也就是說你要刪除其中的指針,是按照指針指向的對象來比較查找的,原因是其內部迭代器的訪問作了特殊處理,因此這點不符合上面應用的需求,當然可以在指針指向的對象中做點手腳,但是這方法有點勉強,應用要的只是刪除指針,而不必關心它指向的對象。為了達到目的又能最大程度地復用代碼,因此改進了STLCollection,簡單地實現了智能指針容器,代碼如下:
1
#ifndef _PTR_CONTAINER_H
2
#define _PTR_CONTAINER_H
3
4
#include "stl_collection.h"
5
#include <boost/smart_ptr.hpp>
6
7
class raw_ptr_compare
8
{
9
public:
10
raw_ptr_compare(void* ptr):m_ptr(ptr)
11
{
12
}
13
bool operator()(const boost::shared_ptr<void>& sp) const
14
{
15
return sp.get()==m_ptr;
16
}
17
private:
18
void* m_ptr;
19
};
20
21
typedef STLCollection<boost::shared_ptr<void> > ptr_container;
22
typedef boost::weak_ptr<ptr_container> wp_ptr_container;
23
24
#ifdef _LOKI_SINGLETON
25
#include <loki/Singleton.h>
26
27
template<class T>
28
struct Loki::CreateUsingNew<boost::weak_ptr<T> >
29
{
30
static boost::weak_ptr<T>* Create()
31
{
32
static boost::shared_ptr<T> sp(new T);
33
static boost::weak_ptr<T> wp = sp;
34
return ℘
35
}
36
37
static void Destroy(boost::weak_ptr<T>* p)
38
{
39
}
40
};
41
typedef ::Loki::SingletonHolder<wp_ptr_container> SingletonSmartPointerContainer;
42
#endif
43
44
#endif

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

應用的示例代碼如下:
1
//在工作線程中,執行調用同步webservice方法login
2
void login_task::Run(const volatile BOOL& bExit)
3
{
4
assert(m_client);
5
login_output out;
6
if (m_client->login(*this,out))
7
{
8
boost::shared_ptr<void> sp(new login_output(out));
9
boost::shared_ptr<ptr_container> sp_ptr = SingletonSmartPointerContainer::Instance().lock();
10
if (sp_ptr)
11
{
12
sp_ptr->add(sp);
13
::PostMessage(m_hWnd,WM_LOGIN,0,(LPARAM)sp.get());
14
}
15
}
16
else
17
{
18
::PostMessage(m_hWnd,WM_LOGIN,1,0);
19
}
20
}
21
//在UI線程中,異步回調WM_LOGIN消息處理
22
LRESULT Cvpn_ca_clientDlg::OnLoginCallback(WPARAM wParam,LPARAM lParam)
23
{
24
if (0==wParam)
25
{
26
login_output* p_out = (login_output*)lParam;
27
boost::shared_ptr<ptr_container> sp = SingletonSmartPointerContainer::Instance().lock();
28
if (sp)
29
{
30
sp->erase(raw_ptr_compare(p_out));
31
}
32
}
33
else if (1==wParam)
34
{
35
36
}
37
return S_OK;
38
}

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
