您的位置:首页 > 编程语言 > C语言/C++

C++进修之STL(一)—— erase和remove特异行动

2014-08-29 17:00 351 查看
C++进修之STL(一)—— erase和remove特异行动

2011年8月16日联系商易上海电子商务网站建设,了解更多
C++的STL经由过程iterator将container和algorithm分别,并经由过程functor供给高可定制性。iterator可以看作是一种契约,algorithm对iterator进行操纵,algorithm很难对container进行直接操纵,这是因为algorithm对container所知甚少,一段代码,若未哄骗操纵对象所知全部信息,将难以达到机能之极,并伴随其它各种调和现象。当然,这种“未知性”是必须的——algorithm对于真正的操纵对象container不克不及做出太多假设,若假设过多,何来一个algorithm可以感化若干不合container的妙举,STL强大威力也将受损不少。

烦琐几句,开个小头,转入正题。 先给出几个关于STL中erase和remove(remove_if等,下称remove类函数)的事实,小小复习:

erase一般作为一个container的成员函数,是真正删除的元素,是物理上的删除
作为算法项目组的remove类函数,是逻辑上的删除,将被删除的元素移动到容器末尾,然后返回新的末尾,此时容器的size不变更
项目组容器供给remove类成员函数,那么代表的是真正物理意义上的删除元素
若是该容器是vector、string或者deque,应用erase-remove idiom或者erase-remove_if idiom
若是该容器是list,应用list::remove或者list:remove_if成员函数
若是该容器是一个associative container,应用asso_con::erase成员函数或者remove_copy_if连络swap等体式格式
有一些斗劲特别的容器具现,比如vector<bool>等,暂不推敲。

更多信息,可以参考《Effective STL》

综上一些信息,可以发明,STL供给给我们的“删除”语义并非真正同一,至少未达到最高层次的同一。有时辰从一种容器换为别的一种容器,修批改改总少不了。

下面,供给一个同一的接口,来删除一个容器中的元素,道理较简单,应用编译器经由过程type deduce获知容器的类型,然后经由过程type traits在编译器就可以决意函数派送决意。比如,编译器知道当前容器是list,那么就会调用list:remove相干的成员函数,机能?inline当然少不了!代码起原是一个STL的教授教化视频上得之,做了些自认为是的简单批改,当然,我的批改可能让代码“恶”了,本身简单用了些容器做测试,法度行动正确,用了trace对象跟踪代码,萍踪合适预期,当然,重在思惟的应用,真正的代码应用还须要经过多次严格测试。

1: //
2: //Source code originally  MSDN Channel 9 Video
3: //Modified by techmush
4: //NOTE: the original code may be perfect, the modified version may be buggy!
5: //Modifies: add string container, add some template parameters, alert some name
6: //            add some notes, code style.
7: //
8:
9: #pragma once
10:
11: #ifndef erasecontainer_h__
12: #define erasecontainer_h__
13:
14: #include <algorithm>
15: #include <deque>
16: #include <forward_list>
17: #include <list>
18: #include <map>
19: #include <set>
20: #include <vector>
21: #include <string>        //string "as" a vector
22: #include <unordered_map>
23: #include <unordered_set>
24:
25: namespace techmush
26: {
27:     namespace detail
28:     {
29:         //erasing behavior like vector: vector, queue, string
30:         struct vector_like_tag
31:         {
32:         };
33:
34:         //erasing behavior like list: list, forward_list
35:         struct list_like_tag
36:         {
37:         };
38:
39:         //erasing behaviod like set: set, map, multiset, multimap, unordered_set, unordered_map
40:         //unordered_multiset, unordered_multimap
41:         struct associative_like_tag
42:         {
43:         };
44:
45:         //type traits for containers
46:         template <typename Cont> struct container_traits;
47:
48:         template <typename Elem, typename Alloc>
49:         struct container_traits<std::vector<Elem,Alloc> >
50:         {
51:             typedef vector_like_tag container_category;
52:         };
53:
54:         template <typename Elem, typename Alloc>
55:         struct container_traits<std::deque<Elem,Alloc> >
56:         {
57:             typedef vector_like_tag container_category;
58:         };
59:
60:         //full specialization traits for string
61:         template <> struct container_traits<std::string>
62:         {
63:             typedef vector_like_tag container_category;
64:         };
65:
66:
67:         template <typename Elem, typename Alloc>
68:         struct container_traits<std::list<Elem,Alloc> >
69:         {
70:             typedef list_like_tag container_category;
71:         };
72:
73:         template <typename Elem, typename Alloc>
74:         struct container_traits<std::forward_list<Elem,Alloc> >
75:         {
76:             typedef list_like_tag container_category;
77:         };
78:
79:         template <typename Key, typename Pred, typename Alloc>
80:         struct container_traits<std::set<Key,Pred,Alloc> >
81:         {
82:             typedef associative_like_tag container_category;
83:
84:         };
85:
86:         //If a multiset contains duplicates, you can""t use erase()
87:         //to remove only the first element of these duplicates.
88:         template <typename Key, typename Pred, typename Alloc>
89:         struct container_traits<std::multiset<Key,Pred,Alloc> >
90:         {
91:             typedef associative_like_tag container_category;
92:         };
93:
94:         template <typename Key, typename Hash, typename Equal, typename Alloc>
95:         struct container_traits<std::unordered_set<Key,Hash,Equal,Alloc> >
96:         {
97:             typedef associative_like_tag container_category;
98:         };
99:
100:         template <typename Key, typename Hash, typename Equal, typename Alloc>
101:         struct container_traits<std::unordered_multiset<Key,Hash,Equal,Alloc> >
102:         {
103:             typedef associative_like_tag container_category;
104:         };
105:
106:         template <typename Key, typename Val, typename Pred, typename Alloc>
107:         struct container_traits<std::map<Key,Val,Pred,Alloc> >
108:         {
109:             typedef associative_like_tag container_category;
110:         };
111:
112:         template <typename Key, typename Val, typename Pred, typename Alloc>
113:         struct container_traits<std::multimap<Key,Val,Pred,Alloc> >
114:         {
115:             typedef associative_like_tag container_category;
116:         };
117:
118:         template <typename Key, typename Val, typename Hash, typename Equal, typename Alloc>
119:         struct container_traits<std::unordered_map<Key,Val,Hash,Equal,Alloc> >
120:         {
121:             typedef associative_like_tag container_category;
122:         };
123:
124:         template <typename Key, typename Val, typename Hash, typename Equal, typename Alloc>
125:         struct container_traits<std::unordered_multimap<Key,Val,Hash,Equal,Alloc> >
126:         {
127:             typedef associative_like_tag container_category;
128:         };
129:
130:
131:         //for vector-like containers, use the erase-remove idiom
132:         template <typename Cont, typename Elem>
133:         inline void erase_helper(Cont& c, const Elem& x, vector_like_tag /*ignored*/)
134:         {
135:             c.erase(std::remove(c.begin(), c.end(), x), c.end());
136:         }
137:
138:         //for vector-like containers, use the erase-remove_if idiom
139:         template <typename Cont, typename Pred>
140:         inline void erase_if_helper(Cont& c, Pred p, vector_like_tag)
141:         {
142:             c.erase(std::remove_if(c.begin(), c.end(), p), c.end());
143:         }
144:
145:         //for list-like containers, use the remove member-function
146:         template <typename Cont, typename Elem>
147:         inline void erase_helper(Cont& c, const Elem& x, list_like_tag)
148:         {
149:             c.remove(x);
150:         }
151:
152:         //for list-like containers, use the remove_if member-function
153:         template <typename Cont, typename Pred>
154:         inline void erase_if_helper(Cont& c, Pred p, list_like_tag)
155:         {
156:             c.remove_if(p);
157:         }
158:
159:         //for associative containers, use the erase member-function
160:         template <typename Cont, typename Elem>
161:         inline void erase_helper(Cont& c, const Elem& x, associative_like_tag)
162:         {
163:             c.erase(x);
164:         }
165:
166:         //When an element of a container is erased, all iterators that point to that
167:         //element are invalidated. Once c.erase(it) reuturns, it has been invalidated.
168:         template <typename Cont, typename Pred>
169:         inline void erase_if_helper(Cont& c, Pred p, associative_like_tag)
170:         {
171:             for (auto it = c.begin(); it != c.end(); /*nothing*/)
172:             {
173:                 if (p(*it))
174:                     c.erase(it++);    //Rebalance the tree
175:                                     //Must have an iterator to the next element
176:                 else                //of c before call erase
177:                     ++ it;
178:             }
179:         }
180:     }
181:
182:     //Interface function for erase
183:     template <typename Cont, typename Elem>
184:     inline void erase(Cont& c, const Elem& x)
185:     {
186:         detail::erase_helper(c, x, typename /*a type*/detail::container_traits<Cont>::container_category());
187:     }
188:
189:
190:     //Interface function for erase_if
191:     template <typename Cont, typename Pred>
192:     inline void erase_if(Cont& c, Pred p)
193:     {
194:         detail::erase_if_helper(c, p, typename detail::container_traits<Cont>::container_category());
195:     }
196: }
197: #endif // erasecontainer_h__


当然,既然选择了C++,就代表选择了折腾(这不也是种乐趣么!),若是容器内是raw pointer呢,你若是想删除,那还到手动去开释资料,万一又有异常产生,呃……好吧,应用auto_ptrs,可以么?(COAP!当然,也可以冒险应用之,重视auto_ptrs的行动特点)。嗯,应用shared_ptrs,较安然。有时辰,不得不消指针,因为我想虚多态。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: