📄 http:^^www.xraylith.wisc.edu^~khan^software^stl^stl.newbie.html
字号:
char buf[1024]; strcpy(buf, "THIS_WOULD_CHANGE_MAGICALLY"); list<char*> list1; list1.push_back(buf); ostream_iterator<char*> citer(cout, " "); copy(list1.begin(), list1.end(), citer); // you should see one string, the one in buf above. strcpy(buf, "YIKES!"); copy(list1.begin(), list1.end(), citer); // SURPRISE. your list is changed now. </pre><p>In general, do not use <tt>char*</tt> as container objects, rather write asimple string class (ask me if you need one) and use that instead.<hr><!WA69><!WA69><!WA69><!WA69><!WA69><!WA69><a href=#pointers>Pointers and STL</a> <br><!WA70><!WA70><!WA70><!WA70><!WA70><!WA70><a href=#index>Back to index</a><hr><a name=class_ptr_char><h3>More gotchas in storing char*</h3></a>Here's an example of a set of strings that can cause lots of headache.<PRE><STRONG>#include</STRONG> <<!WA71><!WA71><!WA71><!WA71><!WA71><!WA71><A HREF="#stl.h">stl.h</A>><STRONG>#include</STRONG> <iostream.h><STRONG>int</STRONG> main<STRONG>(</STRONG><STRONG>int</STRONG><STRONG>,</STRONG> <STRONG>char</STRONG><STRONG>*</STRONG><STRONG>[</STRONG><STRONG>]</STRONG><STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>static</STRONG> <STRONG>char</STRONG><STRONG>*</STRONG> names<STRONG>[</STRONG><STRONG>]</STRONG> <STRONG>=</STRONG> <STRONG>{</STRONG>"<EM>one</EM>"<STRONG>,</STRONG> "<EM>two</EM>"<STRONG>,</STRONG> "<EM>three</EM>"<STRONG>}</STRONG><STRONG>;</STRONG> set<STRONG><</STRONG><STRONG>char</STRONG><STRONG>*</STRONG><STRONG>,</STRONG> less<STRONG><</STRONG><STRONG>char</STRONG><STRONG>*</STRONG><STRONG>></STRONG> <STRONG>></STRONG> name_set<STRONG>;</STRONG> name_set<STRONG>.</STRONG>insert<STRONG>(</STRONG>names<STRONG>[</STRONG>0<STRONG>]</STRONG><STRONG>)</STRONG><STRONG>;</STRONG> name_set<STRONG>.</STRONG>insert<STRONG>(</STRONG>names<STRONG>[</STRONG>1<STRONG>]</STRONG><STRONG>)</STRONG><STRONG>;</STRONG> name_set<STRONG>.</STRONG>insert<STRONG>(</STRONG>names<STRONG>[</STRONG>2<STRONG>]</STRONG><STRONG>)</STRONG><STRONG>;</STRONG> <STRONG>char</STRONG> buf<STRONG>[</STRONG>256<STRONG>]</STRONG><STRONG>;</STRONG> strcpy<STRONG>(</STRONG>buf<STRONG>,</STRONG> "<EM>one</EM>"<STRONG>)</STRONG><STRONG>;</STRONG> <STRONG>const</STRONG> <STRONG>char</STRONG><STRONG>*</STRONG> one <STRONG>=</STRONG> buf<STRONG>;</STRONG> set<STRONG><</STRONG><STRONG>char</STRONG><STRONG>*</STRONG><STRONG>,</STRONG> less<STRONG><</STRONG><STRONG>char</STRONG><STRONG>*</STRONG><STRONG>></STRONG> <STRONG>></STRONG><STRONG>::</STRONG>const_iterator it <STRONG>=</STRONG> name_set<STRONG>.</STRONG>find<STRONG>(</STRONG>one<STRONG>)</STRONG><STRONG>;</STRONG> <STRONG>if</STRONG> <STRONG>(</STRONG>it <STRONG>==</STRONG> name_set<STRONG>.</STRONG>end<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>)</STRONG> <STRONG>{</STRONG> cerr <STRONG><<</STRONG> "<EM>No such name `</EM>" <STRONG><<</STRONG> one <STRONG><<</STRONG> "<EM>' in set!</EM>" <STRONG><<</STRONG> endl<STRONG>;</STRONG> <STRONG>}</STRONG> <STRONG>else</STRONG> <STRONG>{</STRONG> cerr <STRONG><<</STRONG> "<EM>Found name `</EM>" <STRONG><<</STRONG> one <STRONG><<</STRONG> "<EM>' in set.</EM>" <STRONG><<</STRONG> endl<STRONG>;</STRONG> <STRONG>}</STRONG> <STRONG>return</STRONG> 0<STRONG>;</STRONG><STRONG>}</STRONG></PRE><hr><!WA72><!WA72><!WA72><!WA72><!WA72><!WA72><a href=#pointers>Pointers and STL</a> <br><!WA73><!WA73><!WA73><!WA73><!WA73><!WA73><a href=#index>Back to index</a><hr><a name=pointer_wrap><h2>Example of a pointer wrapper for storing in STL containers</h2></a>If you <em>have to</em> store pointers in STL containers, especially thesorted collections such as <tt>set</tt> and <tt>map</tt>, you might wantto wrap the pointers into a simple class that works as a holder for thepointer (<em>who cleans up the memory afterwards</em>?) See <!WA74><!WA74><!WA74><!WA74><!WA74><!WA74><a href=#class_ptr_destruction> here</a> for an example):<p><hr><PRE><STRONG>#include</STRONG> <<!WA75><!WA75><!WA75><!WA75><!WA75><!WA75><A HREF="#stl.h">stl.h</A>><STRONG>#include</STRONG> <iostream.h><EM><STRONG>//</STRONG></EM><EM><STRONG>//</STRONG> Let's say you want to put pointers to X into multiple STL containers.</EM><EM><STRONG>//</STRONG></EM><STRONG>class</STRONG> X <STRONG>{</STRONG>public: X<STRONG>(</STRONG><STRONG>int</STRONG> i<STRONG>)</STRONG> <STRONG>:</STRONG> i_<STRONG>(</STRONG>i<STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>;</STRONG> <STRONG>}</STRONG> X<STRONG>(</STRONG><STRONG>const</STRONG> X<STRONG>&</STRONG> x<STRONG>)</STRONG> <STRONG>:</STRONG> i_<STRONG>(</STRONG>x<STRONG>.</STRONG>i_<STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>}</STRONG> <STRONG>~</STRONG>X<STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>}</STRONG> X<STRONG>&</STRONG> <STRONG>operator</STRONG><STRONG>=</STRONG> <STRONG>(</STRONG><STRONG>const</STRONG> X<STRONG>&</STRONG> x<STRONG>)</STRONG> <STRONG>{</STRONG> i_ <STRONG>=</STRONG> x<STRONG>.</STRONG>i_<STRONG>;</STRONG> <STRONG>}</STRONG> <STRONG>int</STRONG> <STRONG>operator</STRONG><STRONG>(</STRONG><STRONG>)</STRONG><STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>const</STRONG> <STRONG>{</STRONG> <STRONG>return</STRONG> i_<STRONG>;</STRONG> <STRONG>}</STRONG>private: <STRONG>int</STRONG> i_<STRONG>;</STRONG><STRONG>}</STRONG><STRONG>;</STRONG>bool <STRONG>operator</STRONG><STRONG>==</STRONG> <STRONG>(</STRONG><STRONG>const</STRONG> X<STRONG>&</STRONG> x1<STRONG>,</STRONG> <STRONG>const</STRONG> X<STRONG>&</STRONG> x2<STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>return</STRONG> x1<STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>==</STRONG> x2<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>;</STRONG><STRONG>}</STRONG>bool <STRONG>operator</STRONG><STRONG><</STRONG> <STRONG>(</STRONG><STRONG>const</STRONG> X<STRONG>&</STRONG> x1<STRONG>,</STRONG> <STRONG>const</STRONG> X<STRONG>&</STRONG> x2<STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>return</STRONG> x1<STRONG>(</STRONG><STRONG>)</STRONG> <STRONG><</STRONG> x2<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>;</STRONG><STRONG>}</STRONG><EM><STRONG>//</STRONG></EM><EM><STRONG>//</STRONG> Define a simple wrapper class to put into STL containers. This one</EM><EM><STRONG>//</STRONG> simple wraps X.</EM><EM><STRONG>//</STRONG></EM><STRONG>class</STRONG> XPtrWrapper <STRONG>{</STRONG>public: XPtrWrapper<STRONG>(</STRONG>X<STRONG>*</STRONG> x <STRONG>=</STRONG> 0<STRONG>)</STRONG> <STRONG>:</STRONG> x_<STRONG>(</STRONG>x<STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>}</STRONG> XPtrWrapper<STRONG>(</STRONG><STRONG>const</STRONG> XPtrWrapper<STRONG>&</STRONG> xw<STRONG>)</STRONG> <STRONG>:</STRONG> x_<STRONG>(</STRONG>xw<STRONG>.</STRONG>x_<STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>}</STRONG> <STRONG>~</STRONG>XPtrWrapper<STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>}</STRONG> XPtrWrapper<STRONG>&</STRONG> <STRONG>operator</STRONG><STRONG>=</STRONG> <STRONG>(</STRONG><STRONG>const</STRONG> XPtrWrapper<STRONG>&</STRONG> xw<STRONG>)</STRONG> <STRONG>{</STRONG> x_ <STRONG>=</STRONG> xw<STRONG>.</STRONG>x_<STRONG>;</STRONG> <STRONG>}</STRONG> <STRONG>const</STRONG> X<STRONG>*</STRONG> <STRONG>operator</STRONG><STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>const</STRONG> <STRONG>{</STRONG> <STRONG>return</STRONG> x_<STRONG>;</STRONG> <STRONG>}</STRONG> X<STRONG>*</STRONG> <STRONG>operator</STRONG><STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>return</STRONG> x_<STRONG>;</STRONG> <STRONG>}</STRONG>private: X<STRONG>*</STRONG> x_<STRONG>;</STRONG><STRONG>}</STRONG><STRONG>;</STRONG>bool <STRONG>operator</STRONG><STRONG>==</STRONG> <STRONG>(</STRONG><STRONG>const</STRONG> XPtrWrapper<STRONG>&</STRONG> xw1<STRONG>,</STRONG> <STRONG>const</STRONG> XPtrWrapper<STRONG>&</STRONG> xw2<STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>return</STRONG> <STRONG>(</STRONG>xw1<STRONG>.</STRONG><STRONG>operator</STRONG><STRONG>(</STRONG><STRONG>)</STRONG><STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>&&</STRONG> xw2<STRONG>.</STRONG><STRONG>operator</STRONG><STRONG>(</STRONG><STRONG>)</STRONG><STRONG>(</STRONG><STRONG>)</STRONG><STRONG>)</STRONG> <STRONG>?</STRONG> <STRONG>*</STRONG>xw1<STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>==</STRONG> <STRONG>*</STRONG>xw2<STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>:</STRONG> false<STRONG>;</STRONG><STRONG>}</STRONG>bool <STRONG>operator</STRONG><STRONG><</STRONG> <STRONG>(</STRONG><STRONG>const</STRONG> XPtrWrapper<STRONG>&</STRONG> xw1<STRONG>,</STRONG> <STRONG>const</STRONG> XPtrWrapper<STRONG>&</STRONG> xw2<STRONG>)</STRONG> <STRONG>{</STRONG> <STRONG>return</STRONG> <STRONG>(</STRONG>xw1<STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>&&</STRONG> xw2<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>)</STRONG> <STRONG>?</STRONG> <STRONG>*</STRONG>xw1<STRONG>(</STRONG><STRONG>)</STRONG> <STRONG><</STRONG> <STRONG>*</STRONG>xw2<STRONG>(</STRONG><STRONG>)</STRONG> <STRONG>:</STRONG> false<STRONG>;</STRONG><STRONG>}</STRONG><STRONG>void</STRONG> print<STRONG>(</STRONG><STRONG>const</STRONG> XPtrWrapper<STRONG>&</STRONG> xw<STRONG>)</STRONG> <STRONG>{</STRONG> cout <STRONG><<</STRONG> "<EM> </EM>" <STRONG><<</STRONG> <STRONG>(</STRONG><STRONG>*</STRONG>xw<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>)</STRONG><STRONG>(</STRONG><STRONG>)</STRONG><STRONG>;</STRONG><STRONG>}</STRONG><STRONG>int</STRONG> main<STRONG>(</STRONG><STRONG>int</STRONG><STRONG>,</STRONG> <STRONG>char</STRONG><STRONG>*</STRONG><STRONG>[</STRONG><STRONG>]</STRONG><STRONG>)</STRONG> <STRONG>{</STRONG> XPtrWrapper bucket<STRONG>[</STRONG>5<STRONG>]</STRONG><STRONG>;</STRONG> <STRONG>for</STRONG><STRONG>(</STRONG><STRONG>int</STRONG> i <STRONG>=</STRONG> 0<STRONG>;</STRONG> i <STRONG><</STRONG> 5<STRONG>;</STRONG> <STRONG>++</STRONG>i<STRONG>)</STRONG> <STRONG>{</STRONG> bucket<STRONG>[</STRONG>i<STRONG>]</STRONG> <STRONG>=</STRONG> XPtrWrapper<STRONG>(</STRONG><STRONG>new</STRONG> X<STRONG>(</STRONG>i <STRONG>*</STRONG> i<STRONG>)</STRONG><STRONG>)</STRONG><STRONG>;</STRONG> <STRONG>}</STRONG> random_shuffle<STRONG>(</STRONG>bucket<STRONG>,</STRONG> bucket <STRONG>+</STRONG> 5<STRONG>)</STRONG><STRONG>;</STRONG> list<STRONG><</STRONG>XPtrWrapper<STRONG>></STRONG> list1<STRONG>;</STRONG> copy<STRONG>(</STRONG>bucket<STRONG>,</STRONG> bucket <STRONG>+</STRONG> 5<STRONG>,</STRONG> back_insert_iterator<STRONG><</STRONG>list<STRONG><</STRONG>XPtrWrapper<STRONG>></STRONG> <STRONG>></STRONG> <STRONG>(</STRONG>list1<STRONG>)</STRONG> <STRONG>)</STRONG><STRONG>;</STRONG> cout <STRONG><<</STRONG> "<EM>List of XPtrWrapper: (</EM>"<STRONG>;</STRONG> for_each<STRONG>(</STRONG>list1<STRONG>.</STRONG>begin<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>,</STRONG> list1<STRONG>.</STRONG>end<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>,</STRONG> print<STRONG>)</STRONG><STRONG>;</STRONG> cout <STRONG><<</STRONG> "<EM>)</EM>" <STRONG><<</STRONG> endl<STRONG>;</STRONG> <EM><STRONG>//</STRONG></EM> <EM><STRONG>//</STRONG> now put these XPtrWrappers into a set. Note that I can use</EM> <EM><STRONG>//</STRONG> greater<XPtrWrapper> since I've defined operator> for it.</EM> <EM><STRONG>//</STRONG></EM> set<STRONG><</STRONG>XPtrWrapper<STRONG>,</STRONG> greater<STRONG><</STRONG>XPtrWrapper<STRONG>></STRONG> <STRONG>></STRONG> set1<STRONG>;</STRONG> copy<STRONG>(</STRONG>list1<STRONG>.</STRONG>begin<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>,</STRONG> list1<STRONG>.</STRONG>end<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>,</STRONG> insert_iterator<STRONG><</STRONG>set<STRONG><</STRONG>XPtrWrapper<STRONG>,</STRONG> greater<STRONG><</STRONG>XPtrWrapper<STRONG>></STRONG> <STRONG>></STRONG> <STRONG>></STRONG> <STRONG>(</STRONG>set1<STRONG>,</STRONG> set1<STRONG>.</STRONG>begin<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>)</STRONG> <STRONG>)</STRONG><STRONG>;</STRONG> cout <STRONG><<</STRONG> "<EM>Set of XPtrWrapper : [</EM>"<STRONG>;</STRONG> for_each<STRONG>(</STRONG>set1<STRONG>.</STRONG>begin<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>,</STRONG> set1<STRONG>.</STRONG>end<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>,</STRONG> print<STRONG>)</STRONG><STRONG>;</STRONG> cout <STRONG><<</STRONG> "<EM>]</EM>" <STRONG><<</STRONG> endl<STRONG>;</STRONG> <EM><STRONG>//</STRONG></EM> <EM><STRONG>//</STRONG> now put these integers into a deque. </EM> <EM><STRONG>//</STRONG></EM> deque<STRONG><</STRONG>XPtrWrapper<STRONG>></STRONG> deque1<STRONG>;</STRONG> copy<STRONG>(</STRONG>list1<STRONG>.</STRONG>begin<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>,</STRONG> list1<STRONG>.</STRONG>end<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>,</STRONG> back_insert_iterator<STRONG><</STRONG>deque<STRONG><</STRONG>XPtrWrapper<STRONG>></STRONG> <STRONG>></STRONG> <STRONG>(</STRONG>deque1<STRONG>)</STRONG> <STRONG>)</STRONG><STRONG>;</STRONG> cout <STRONG><<</STRONG> "<EM>Deque of XPtrWrapper : (</EM>"<STRONG>;</STRONG> for_each<STRONG>(</STRONG>deque1<STRONG>.</STRONG>begin<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>,</STRONG> deque1<STRONG>.</STRONG>end<STRONG>(</STRONG><STRONG>)</STRONG><STRONG>,</STRONG> print<STRONG>)</STRONG><STRONG>;</STRONG> cout <STRONG><<</STRONG> "<EM>)</EM>" <STRONG><<</STRONG> endl<STRONG>;</STRONG> <STRONG>return</STRONG> 0<STRONG>;</STRONG><STRONG>}</STRONG></PRE><hr><p>And the output is:<hr><pre>List of XPtrWrapper: ( 4 0 16 1 9)Set of XPtrWrapper : [ 16 9 4 1 0]Deque of XPtrWrapper : ( 4 0 16 1 9)</pre><p><hr><!WA76><!WA76><!WA76><!WA76><!WA76><!WA76><a href=#pointers>Pointers and STL</a> <br><!WA77><!WA77><!WA77><!WA77><!WA77><!WA77><a href=#index>Back to index</a><hr><a name=pointer_deriv><h2> How do I store derived objects in STL containers?</h2></a>Consider a CAD application: you have lots of objects on a screen that allderive from the same base object. How would you store the derived objectsin an STL container? Let's assume all derived objects have a set ofvirtual functions (and use RTTI if you have it). I've done it 3 differentways:<p><ol><li> <!WA78><!WA78><!WA78><!WA78><!WA78><!WA78><a href=#seq_pointer> Store the pointer itself in the container</a>. You have to explicitly deallocate the memory later on of course. Also, not all STL implementations seem to handle storage of pointers uniformly, so I would suggest using a wrapper shown below.<li> <!WA79><!WA79><!WA79><!WA79><!WA79><!WA79><a href=#pointer_deriv_hard> Hard-coded wrapper</a> that takes a pointer to the base class<li> <!WA80><!WA80><!WA80><!WA80><!WA80><!WA80><a href=#pointer_deriv_template> Templated pointer wrapper</a> that takes a pointer to the base class</ol><p><a name=pointer_deriv_hard><h3> Hard-coded wrapper that takes a pointer to the base class</h3></a>The following example shows 2 classes derived from <tt>Base</tt>, <tt>derived1</tt> and <tt>derived2</tt> and a wrapper<tt>BaseWrapper</tt>. The wrapper class <b>assumes</b> that the base classprovides a virtual <tt>clone</tt> facility and does the memorymanagement. <p><em>Note: After the new'd Base derivative is passed to the wrapper, it owns it and deletes it in the destructor</em>.<p><hr><PRE><STRONG>#include</STRONG> <<!WA81><!WA81><!WA81><!WA81><!WA81><!WA81><A HREF="#stl.h">stl.h</A>><STRONG>#include</STRONG> <string.h><STRONG>#include</STRONG> <iostream.h><EM><STRONG>//</STRONG></EM><EM><STRONG>//</STRONG> abstract base class</EM><EM><STRONG>//</STRONG></EM><STRONG>class</STRONG> Base <STRONG>{</STRONG>public:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -