在《
基于stl序列容器实现的通用集合类》一文中,已经讲到了具体实现,近来因再次用到它又改进完善了,主要体现在以下几点:1)增加了查找操作方法,支持按值类型和谓词条件两种方式。2)增加重载了按值类型和谓词条件2种方式删除元素的方法。3)增加了2个模板参数以支持线程安全,一个是线程模型模板类,一个是互斥锁类,使用loki库来实现,因此所有方法现在都是线程安全的,当需要在多线程环境使用时,注意这里是对象级别锁而不是类级别锁,只需定义loki中的宏LOKI_OBJECT_LEVEL_THREADING即可;当在单线程环境使用时,LOKI_CLASS_LEVEL_THREADING和LOKI_OBJECT_LEVEL_THREADING两个宏都不要定义。代码如下:
1
#ifndef _STL_COLLECTION_H
2
#define _STL_COLLECTION_H
3![](/Images/OutliningIndicators/None.gif)
4
#include <memory>
5
#include <vector>
6
#include <loki/Threads.h>
7![](/Images/OutliningIndicators/None.gif)
8![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**
9
@class STLCollection
10
@brief 基于STL容器(vector,list,deque)实现的数据结构通用集合类
11![](/Images/OutliningIndicators/InBlock.gif)
12
* 提供以索引作为外参的以下公共通用接口
13
* add --- 向前或向后增加单个元素
14
* insert --- 插入单个元素
15
* erase --- 删除单个或多个元素
16
* set --- 修改某个元素
17
* get --- 获取某个元素
18
* find --- 查找某个元素
19
* front --- 获取第一个元素
20
* back --- 获取最后一个元素
21
*/
22![](/Images/OutliningIndicators/None.gif)
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![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
31
typedef U<T> Allocator;
32
typedef C<T,Allocator> base;
33
typedef STLCollection<T,ThreadModel,MutexPolicy,C,U> self;
34![](/Images/OutliningIndicators/InBlock.gif)
35
public:
36
STLCollection()
37![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
38
}
39
explicit STLCollection(const Allocator& al)
40
:base(al)
41![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
42
}
43
explicit STLCollection(size_t n)
44
:base(n)
45![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
46
}
47
STLCollection(size_t n,const T& t)
48
:base(n,t)
49![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
50
}
51
STLCollection(size_t n,const T& t,const Allocator& al)
52
:base(n,t,al)
53![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
54
}
55
STLCollection(const STLCollection& right)
56
:base(right)
57![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
58
}
59![](/Images/OutliningIndicators/InBlock.gif)
60
template<class InputIterator>
61
STLCollection(InputIterator first,InputIterator last)
62
:base(first,last)
63![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
64
}
65![](/Images/OutliningIndicators/InBlock.gif)
66
template<class InputIterator>
67
STLCollection(InputIterator first,InputIterator last,const Allocator& al)
68
:base(first,last,al)
69![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
70
}
71
~STLCollection()
72![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
73
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
74
}
75![](/Images/OutliningIndicators/InBlock.gif)
76
public:
77
using base::erase;
78
using base::insert;
79
using base::front;
80
using base::back;
81![](/Images/OutliningIndicators/InBlock.gif)
82
void add(const T& t,bool append = true)
83![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
92
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
93
insert_impl(index,t,typename std::iterator_traits<typename base::iterator>::iterator_category());
94
}
95![](/Images/OutliningIndicators/InBlock.gif)
96
void erase(size_t index)
97![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/InBlock.gif)
120
void set(size_t index,const T& t)
121![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
122
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
123
T* p = get(index);
124
if (p) *p = t;
125
}
126![](/Images/OutliningIndicators/InBlock.gif)
127
T* get(size_t index)
128![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
134
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
135
return get_impl(index,typename std::iterator_traits<typename base::iterator>::iterator_category());
136
}
137![](/Images/OutliningIndicators/InBlock.gif)
138
T* find(const T& val,size_t* index)
139![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
140
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
141![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
149
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
150![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
159
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
160![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
169
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
170![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
177
T* front()
178![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
179
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
180![](/Images/OutliningIndicators/InBlock.gif)
181
if (base::empty()) return NULL;
182
return &base::front();
183
}
184
const T* front() const
185![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
186
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
187![](/Images/OutliningIndicators/InBlock.gif)
188
if (base::empty()) return NULL;
189
return &base::front();
190
}
191![](/Images/OutliningIndicators/InBlock.gif)
192
T* back()
193![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
194
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
195![](/Images/OutliningIndicators/InBlock.gif)
196
if (base::empty()) return NULL;
197
return &base::back();
198
}
199
const T* back() const
200![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
201
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
202![](/Images/OutliningIndicators/InBlock.gif)
203
if (base::empty()) return NULL;
204
return &base::back();
205
}
206![](/Images/OutliningIndicators/InBlock.gif)
207
bool is_empty() const
208![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
209
typename ThreadModel<self,MutexPolicy>::Lock guard(lock_);
210
return base::empty();
211
}
212![](/Images/OutliningIndicators/InBlock.gif)
213
private:
214
void insert_impl(size_t index,const T& t,std::random_access_iterator_tag tag)
215![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
216
if (index < base::size())
217![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
223
if (index < base::size())
224![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
232
if (index < base::size())
233![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
234
base::erase(base::begin()+index);
235
}
236
}
237
void erase_impl(size_t index,std::input_iterator_tag tag)
238![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
239
if (index < base::size())
240![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
248
end = std::min(end,base::size());
249
if (beg < end)
250![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
256
end = std::min(end,base::size());
257
if (beg < end)
258![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/None.gif)
295
#endif 现在来看一下它的应用,一个网络通讯项目,由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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
4
#include "stl_collection.h"
5
#include <boost/smart_ptr.hpp>
6![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
7
class raw_ptr_compare
8![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
9
public:
10
raw_ptr_compare(void* ptr):m_ptr(ptr)
11![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
12
}
13
bool operator()(const boost::shared_ptr<void>& sp) const
14![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
15
return sp.get()==m_ptr;
16
}
17
private:
18
void* m_ptr;
19
};
20![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
21
typedef STLCollection<boost::shared_ptr<void> > ptr_container;
22
typedef boost::weak_ptr<ptr_container> wp_ptr_container;
23![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
24
#ifdef _LOKI_SINGLETON
25
#include <loki/Singleton.h>
26![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
27
template<class T>
28
struct Loki::CreateUsingNew<boost::weak_ptr<T> >
29![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
30
static boost::weak_ptr<T>* Create()
31![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
32
static boost::shared_ptr<T> sp(new T);
33
static boost::weak_ptr<T> wp = sp;
34
return ℘
35
}
36![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
37
static void Destroy(boost::weak_ptr<T>* p)
38![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
39
}
40
};
41
typedef ::Loki::SingletonHolder<wp_ptr_container> SingletonSmartPointerContainer;
42
#endif
43![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
44
#endif 应用的示例代码如下:
1
//在工作线程中,执行调用同步webservice方法login
2
void login_task::Run(const volatile BOOL& bExit)
3![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
4
assert(m_client);
5
login_output out;
6
if (m_client->login(*this,out))
7![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
12
sp_ptr->add(sp);
13
::PostMessage(m_hWnd,WM_LOGIN,0,(LPARAM)sp.get());
14
}
15
}
16
else
17![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
24
if (0==wParam)
25![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
26
login_output* p_out = (login_output*)lParam;
27
boost::shared_ptr<ptr_container> sp = SingletonSmartPointerContainer::Instance().lock();
28
if (sp)
29![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
30
sp->erase(raw_ptr_compare(p_out));
31
}
32
}
33
else if (1==wParam)
34![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
35![](/Images/OutliningIndicators/InBlock.gif)
36
}
37
return S_OK;
38
}
posted on 2011-10-21 18:43
春秋十二月 阅读(3135)
评论(1) 编辑 收藏 引用 所属分类:
Opensrc