﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-colorful-随笔分类-boost</title><link>http://www.cppblog.com/colorful/category/19318.html</link><description>zc qq:1337220912</description><language>zh-cn</language><lastBuildDate>Fri, 16 Oct 2015 03:01:59 GMT</lastBuildDate><pubDate>Fri, 16 Oct 2015 03:01:59 GMT</pubDate><ttl>60</ttl><item><title>STL的remove函数和list的remove成员函数</title><link>http://www.cppblog.com/colorful/archive/2015/10/14/212010.html</link><dc:creator>多彩人生</dc:creator><author>多彩人生</author><pubDate>Wed, 14 Oct 2015 07:50:00 GMT</pubDate><guid>http://www.cppblog.com/colorful/archive/2015/10/14/212010.html</guid><wfw:comment>http://www.cppblog.com/colorful/comments/212010.html</wfw:comment><comments>http://www.cppblog.com/colorful/archive/2015/10/14/212010.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/colorful/comments/commentRss/212010.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colorful/services/trackbacks/212010.html</trackback:ping><description><![CDATA[<div>http://www.cnblogs.com/kinuxroot/archive/2013/01/25/stl_remove_problem.html<br /><br /><div id="cnblogs_post_body" style="margin-bottom: 20px; word-break: break-word; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 20.7999992370605px;"><p style="margin-top: 10px; margin-bottom: 10px;">今天看书刚刚看的，就记录下来吧。这可能是老生常谈了，权且作为一个警醒的例子吧。</p><p style="margin-top: 10px; margin-bottom: 10px;">大家都知道STL有两个非常重要的组成部分，容器和算法。</p><p style="margin-top: 10px; margin-bottom: 10px;">算法就是一个个的函数，通过迭代器和容器关联在一起，完成一些工作。</p><p style="margin-top: 10px; margin-bottom: 10px;">算法和容器的分离为程序设计提供了很大的灵活性，但是也带来了一些负面效果，下面我讲的这个问题就是一个例子。</p><p style="margin-top: 10px; margin-bottom: 10px;">STL的算法里有一个remove函数，而list自身也有一个remove函数，功能都是一样的，移除某一个元素，那我们应该使用哪一个呢？</p><p style="margin-top: 10px; margin-bottom: 10px;">看一下下面这段程序</p><div style="margin: 5px 0px; font-size: 12px !important;"><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #075db3; text-decoration: underline; border: none !important;"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="border: none !important;" /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New' !important;"><span style="color: #008080; line-height: 1.5 !important;"> 1</span>     list&lt;<span style="color: #0000ff; line-height: 1.5 !important;">int</span>&gt;<span style="line-height: 1.5 !important;"> numbers; </span><span style="color: #008080; line-height: 1.5 !important;"> 2</span>  <span style="color: #008080; line-height: 1.5 !important;"> 3</span>     <span style="color: #0000ff; line-height: 1.5 !important;">for</span> ( <span style="color: #0000ff; line-height: 1.5 !important;">int</span> number = <span style="color: #800080; line-height: 1.5 !important;">0</span>; number &lt;= <span style="color: #800080; line-height: 1.5 !important;">6</span>; number ++<span style="line-height: 1.5 !important;"> ) { </span><span style="color: #008080; line-height: 1.5 !important;"> 4</span> <span style="line-height: 1.5 !important;">        numbers.push_front(number); </span><span style="color: #008080; line-height: 1.5 !important;"> 5</span> <span style="line-height: 1.5 !important;">        numbers.push_back(number); </span><span style="color: #008080; line-height: 1.5 !important;"> 6</span> <span style="line-height: 1.5 !important;">    } </span><span style="color: #008080; line-height: 1.5 !important;"> 7</span>  <span style="color: #008080; line-height: 1.5 !important;"> 8</span> <span style="line-height: 1.5 !important;">    copy(numbers.begin(), numbers.end(), </span><span style="color: #008080; line-height: 1.5 !important;"> 9</span>             ostream_iterator&lt;<span style="color: #0000ff; line-height: 1.5 !important;">int</span>&gt;(cout, <span style="color: #800000; line-height: 1.5 !important;">"</span> <span style="color: #800000; line-height: 1.5 !important;">"</span><span style="line-height: 1.5 !important;">)); </span><span style="color: #008080; line-height: 1.5 !important;">10</span>     cout &lt;&lt;<span style="line-height: 1.5 !important;"> endl; </span><span style="color: #008080; line-height: 1.5 !important;">11</span>  <span style="color: #008080; line-height: 1.5 !important;">12</span>     <span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> remove algorithm will remove element but not erase the element from container </span><span style="color: #008080; line-height: 1.5 !important;">13</span>     <span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> it will return the logical desination of container</span> <span style="color: #008080; line-height: 1.5 !important;">14</span>     list&lt;<span style="color: #0000ff; line-height: 1.5 !important;">int</span>&gt;::iterator endOfNumbers = remove(numbers.begin(), numbers.end(), <span style="color: #800080; line-height: 1.5 !important;">3</span><span style="line-height: 1.5 !important;">); </span><span style="color: #008080; line-height: 1.5 !important;">15</span>  <span style="color: #008080; line-height: 1.5 !important;">16</span> <span style="line-height: 1.5 !important;">    copy(numbers.begin(), numbers.end(), </span><span style="color: #008080; line-height: 1.5 !important;">17</span>             ostream_iterator&lt;<span style="color: #0000ff; line-height: 1.5 !important;">int</span>&gt;(cout, <span style="color: #800000; line-height: 1.5 !important;">"</span> <span style="color: #800000; line-height: 1.5 !important;">"</span><span style="line-height: 1.5 !important;">)); </span><span style="color: #008080; line-height: 1.5 !important;">18</span>     cout &lt;&lt; endl;</pre><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #075db3; text-decoration: underline; border: none !important;"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="border: none !important;" /></a></span></div></div><p style="margin-top: 10px; margin-bottom: 10px;">输出是什么呢？</p><p style="margin-top: 10px; margin-bottom: 10px;">第一行肯定是6 5 4 3 2 1 0 0 1 2 3 4 5 6，那么第二行会输出什么？</p><p style="margin-top: 10px; margin-bottom: 10px;">如果是没有仔细看过STL的人肯定会认为remove(number.begin(), numbers.end(), 3)会移除所有值为3的元素。所以输出是：6 5 4 2 1 0 0 1 2 4 5 6。</p><p style="margin-top: 10px; margin-bottom: 10px;">但是，我们看一下它真正的输出：</p><p style="margin-top: 10px; margin-bottom: 10px;">6 5 4 2 1 0 0 1 2 4 5 6 5 6</p><p style="margin-top: 10px; margin-bottom: 10px;">你可能会非常惊讶，为什么最后会多出5和6两个数呢？</p><p style="margin-top: 10px; margin-bottom: 10px;">我们来讲一下remove算法的原理。</p><p style="margin-top: 10px; margin-bottom: 10px;">remove算法工作时<strong>并不是直接把元素删除，而是用后面的元素替代前面的元素</strong>，也即是说如果我对1234这个序列remove 2，返回的序列是 1344（3被复制到2的位置，4被复制到3的位置）。</p><p style="margin-top: 10px; margin-bottom: 10px;">这样上面的例子就好解释了，那两个3的元素并没有被移除，而是<strong>用后面的元素覆盖了前面的元素</strong>。多出的那两个数没有被移除掉而已。</p><p style="margin-top: 10px; margin-bottom: 10px;">那么我们应该如何真正完成移除呢？remove函数会返回一个迭代器，那个迭代器是这个序列的逻辑终点，也即是我代码里的endOfNumbers，它指向倒数第二个5上。</p><p style="margin-top: 10px; margin-bottom: 10px;">于是我们要利用list的erase函数完成元素移除</p><div style="margin: 5px 0px; font-size: 12px !important;"><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New' !important;">numbers.erase(endOfNumbers, numbers.end());</pre></div><p style="margin-top: 10px; margin-bottom: 10px;">这样我们就完成了我们的工作，稍稍有点曲折&#8230;&#8230;</p><p style="margin-top: 10px; margin-bottom: 10px;">其实我们可以把这两步放在一起，比如如果我想接着移除所有值为2的元素</p><div style="margin: 5px 0px; font-size: 12px !important;"><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New' !important;">numbers.erase(remove(numbers.begin(), numbers.end(), <span style="color: #800080; line-height: 1.5 !important;">2</span>), numbers.end());</pre></div><p style="margin-top: 10px; margin-bottom: 10px;">这样我们就可以一步到位了。</p><p style="margin-top: 10px; margin-bottom: 10px;">但是这样好么？</p><p style="margin-top: 10px; margin-bottom: 10px;">不好。</p><p style="margin-top: 10px; margin-bottom: 10px;">大家会发现，remove函数的原理是复制而不是指针的移动（因为函数操纵的是迭代器，而C++的迭代器没有定义删除操作），这样会带来一个问题：我们使用list是因为它的修改的效率非常高，改变一下指针就可以了。而这里我们复制了元素，如果在vector中，可能还是高效的，因为vector无论如何都要复制，而对于list就不是如此了，<strong>会极度降低我们的效率。</strong></p><p style="margin-top: 10px; margin-bottom: 10px;">那我们怎么办呢？</p><p style="margin-top: 10px; margin-bottom: 10px;">答案是使用list自己的remove函数</p><div style="margin: 5px 0px; font-size: 12px !important;"><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New' !important;">numbers.remove(<span style="color: #800080; line-height: 1.5 !important;">1</span>);</pre></div><p style="margin-top: 10px; margin-bottom: 10px;">我们可以这样删除所有值为1的元素。</p><p style="margin-top: 10px; margin-bottom: 10px;">也即是说，如果要删除list中的元素，<strong>我们应该使用list的remove成员函数，而不是remove算法</strong>！</p><p style="margin-top: 10px; margin-bottom: 10px;"><strong>小结</strong></p><p style="margin-top: 10px; margin-bottom: 10px;">我们都知道，STL是一个效率、复用性、灵活性折衷的产物，其中效率至关重要，所以STL已经禁止了一些效率低的操作（比如list的随机访问），而鼓励你去使用其它的容器。</p><p style="margin-top: 10px; margin-bottom: 10px;">但是，<strong>在算法中，为了灵活性，STL还是会牺牲一些东西</strong>，比如我们这个例子。</p><p style="margin-top: 10px; margin-bottom: 10px;">个人觉得，STL作为C++标准库的一个组成部分，特点和C++本身一模一样，强大而复杂，有些地方难以理解，很多细节需要学习注意，我们要学会避免陷入某些陷阱之中，比如这个例子就是一个效率陷阱。</p><p style="margin-top: 10px; margin-bottom: 10px;">其它更多的陷阱是错误处理方面的，STL本身并没有规定过多的错误处理，大部分的错误处理都交给了我们，理由很简单：<strong>性能至上</strong>，如果一个东西自身没有错误检查，我们可以包装一个带错误检查的类；但是如果这个东西自身就带了错误检查，那么我们就没有任何方法提升它的效率了。这也是很多C和C++库的设计原则。</p><p style="margin-top: 10px; margin-bottom: 10px;">所以，<strong>很多时候，需要我们深入细节</strong>，然后再决定到底怎么做。因为C++就是如此：有很多路可以走，需要我们自己选择最好的一条路。</p></div><div style="clear: both; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 20.7999992370605px;"></div><div id="blog_post_info_block" style="margin-top: 20px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 20.7999992370605px;"><div id="BlogPostCategory" style="margin-bottom: 10px;">分类:&nbsp;<a href="http://www.cnblogs.com/kinuxroot/category/448779.html" style="color: #075db3;">C++</a></div></div></div><img src ="http://www.cppblog.com/colorful/aggbug/212010.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colorful/" target="_blank">多彩人生</a> 2015-10-14 15:50 <a href="http://www.cppblog.com/colorful/archive/2015/10/14/212010.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>shared_from_this 几个值得注意的地方</title><link>http://www.cppblog.com/colorful/archive/2012/06/22/179817.html</link><dc:creator>多彩人生</dc:creator><author>多彩人生</author><pubDate>Fri, 22 Jun 2012 14:42:00 GMT</pubDate><guid>http://www.cppblog.com/colorful/archive/2012/06/22/179817.html</guid><wfw:comment>http://www.cppblog.com/colorful/comments/179817.html</wfw:comment><comments>http://www.cppblog.com/colorful/archive/2012/06/22/179817.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colorful/comments/commentRss/179817.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colorful/services/trackbacks/179817.html</trackback:ping><description><![CDATA[<div><span style="color: #ff0000;" color="#ff0000">shared_from_this()是 enable_shared_from_this&lt;T&gt;的成员  函数，返回shared_ptr&lt;T&gt;。首先需要注意的是，这个函数仅在shared_ptr&lt;T&gt;的构造函数被调用之后才能使   用。原因是enable_shared_from_this::weak_ptr并不在构造函数中设置，而是在shared_ptr&lt;T&gt;的  构造函数中设置。</span> <br /><br />如下代码是错误的： <div> <div><ol><li>class D:public <span href="http://bbs.rosoo.net/tag.php?name=boost">boost</span>::enable_shared_from_this&lt;D&gt;</li><li>{</li><li>public:</li><li>&nbsp; &nbsp; D()</li><li>&nbsp; &nbsp; {</li><li>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;boost::shared_ptr&lt;D&gt; p=shared_from_this();</li><li>&nbsp; &nbsp; }</li><li>};</li></ol></div> 复制代码</div> 原 因很简单，在D的构造函数中虽然可以保证enable_shared_from_this&lt;D&gt;的构造函数已经被调用，但正如前面所 说，weak_ptr还没有设置。 <br /><br />如下代码也是错误的： <div> <div><ol><li>class D:public boost::enable_shared_from_this&lt;D&gt;</li><li>{</li><li>public:</li><li>&nbsp; &nbsp; void func()</li><li>&nbsp; &nbsp; {</li><li>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;boost::shared_ptr&lt;D&gt; p=shared_from_this();</li><li>&nbsp; &nbsp; }</li><li>};</li><li>void main()</li><li>{</li><li>&nbsp; &nbsp; D d;</li><li>&nbsp; &nbsp; d.func();</li><li>}</li></ol></div> 复制代码</div> 错 误原因同上。 <br /><br />如下代码是正确的： <div> <div><ol><li>void main()</li><li>{</li><li>&nbsp; &nbsp; boost::shared_ptr&lt;D&gt; d(new D);</li><li>&nbsp; &nbsp; d-&gt;func();</li><li>}</li></ol></div> 复制代码</div> 这 里boost::shared_ptr&lt;D&gt; d(new  D)实际上执行了3个动作：首先调用enable_shared_from_this&lt;D&gt;的构造函数；其次调用D的构造函数；最后调用  shared_ptr&lt;D&gt;的构造函数。是第3个动作设置了enable_shared_from_this&lt;D&gt;的  weak_ptr，而不是第1个动作。这个地方是很违背c++常理和逻辑的，必须小心。 <br /><br /><span style="color: #0000ff;" color="#0000ff">结论是，不要在构造函数中使用shared_from_this；其次，如果要使用shared_ptr，则应该 在所有地方均使用，不能使用D d这种方式，也决不要传递裸指针。 </span>&nbsp;&nbsp;<br /><br />另一个值得注意的地方是在类的继承树中不能有2个或更多个enable_shared_from_this&lt;T&gt;。例如如下代码是错误的： <div> <div><ol><li>class A:public boost::enable_shared_from_this&lt;A&gt;</li><li>{</li><li>public:</li><li>&nbsp; &nbsp; A():a(1){}</li><li>&nbsp; &nbsp; virtual ~A(){}</li><li>&nbsp; &nbsp; boost::shared_ptr&lt;A&gt; get_ptra(){return shared_from_this();}</li><li>&nbsp; &nbsp; int a;</li><li>};</li><li>class B:public A,public boost::enable_shared_from_this&lt;B&gt;</li><li>{</li><li>public:</li><li>&nbsp; &nbsp; B():b(2){}</li><li>&nbsp; &nbsp; boost::shared_ptr&lt;B&gt; get_ptrb()</li><li>&nbsp; &nbsp; {</li><li>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;return boost::enable_shared_from_this&lt;B&gt;::shared_from_this();</li><li>&nbsp; &nbsp; }</li><li>&nbsp; &nbsp; int b;</li><li>};</li><li>int _tmain(int argc, _TCHAR* argv[])</li><li>{</li><li>&nbsp; &nbsp; {</li><li>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;boost::shared_ptr&lt;B&gt; x(new B);</li><li>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;boost::shared_ptr&lt;A&gt; a1 = x-&gt;get_ptra();</li><li>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;boost::shared_ptr&lt;B&gt; b1 = x-&gt;get_ptrb();</li><li>&nbsp; &nbsp; }</li><li>&nbsp; &nbsp; return 0;</li><li>}</li></ol></div> 复制代码</div> 注 意上面代码中，B同时拥有2个enable_shared_from_this的基类，一个是  enable_shared_from_this&lt;A&gt;，另一个是enable_shared_from_this&lt;B&gt;。在  boost::shared_ptr&lt;B&gt; x(new  B);这行代码中，shared_ptr&lt;B&gt;的构造函数仅会设置2个基类中的一个的weak_ptr。在上面的例子中，仅设置  enable_shared_from_this&lt;A&gt;的。如果修改B的定义为： <br /><br />class B:public boost::enable_shared_from_this&lt;B&gt;,public A， <br /><br />则仅设置enable_shared_from_this&lt;B&gt;的weak_ptr。很明显都是错误的。 <br /><br />那么enable_shared_from_this以及shared_ptr为何要如此实现呢？又为什么会有如此怪异的结果呢？ <br /><br />首先考察shared_ptr的构造函数： <div> <div><ol><li>template&lt;class Y&gt;</li><li>explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete</li><li>{</li><li>&nbsp; &nbsp; boost::detail::sp_enable_shared_from_this( pn, p, p );</li><li>}</li><li>template&lt;class T, class Y&gt; void sp_enable_shared_from_this(  shared_count const &amp; pn, boost::enable_shared_from_this&lt;T&gt;  const * pe, Y const * px )</li><li>{</li><li>&nbsp; &nbsp; if(pe != 0) pe-&gt;_internal_weak_this._internal_assign(const_cast&lt;Y*&gt;(px), pn);</li><li>}</li></ol></div> 复制代码</div> 注 意这个sp_enable_shared_from_this是一个模板函数，而且仅调用了一次，所以不可能2个  enable_shared_from_this基类的weak_ptr都被赋值。但问题在于，在调换了B的定义之后结果居然是不一样的。这里有一个很隐   秘的编译器BUG。按道理来说，编译器在编译这段代码时，应该注意到无法真正决断该怎么实例化sp_enable_shared_from_this并且  报一个错，但vc 2008并没有报错，而是通过编译了。（g++会在此处报错） <br /><br />那么正确的解法是怎样的呢？ <div> <div><ol><li>class B:public A</li><li>{</li><li>public:</li><li>&nbsp; &nbsp; B():b(2){}</li><li>&nbsp; &nbsp; boost::shared_ptr&lt;B&gt; get_ptrb()</li><li>&nbsp; &nbsp; {</li><li>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;return boost::dynamic_pointer_cast&lt;B&gt;(shared_from_this());</li><li>&nbsp; &nbsp; }</li><li>&nbsp; &nbsp; int b;</li><li>};</li></ol></div> 复制代码</div> 注 意到这里B并没有直接继承enable_shared_from_this，而是使用dynamic_pointer_cast进行了类型转换。 <br /><br />关于为什么enable_shared_from_this是这样实现的，可以参看作者原文： <br /><br />Every  enable_shared_from_this base contains a weak_ptr, The shared_ptr  constructor looks up the enable_shared_from_this base and initializes  its weak_ptr accordingly. This doesn't work when there are<br />two or more enable_shared_from_this bases, though. <br /><br />I  could put the weak_ptr in a virtual polymorphic base. This would force  polymorphism on all clients of enable_shared_from_this... probably  acceptable. It will also force a dynamic_pointer_cast in every<br />shared_from_this, and this may be harder to swallow, particularly in cases where RTTI is off. So I'm not sure. <br /><br />If  you do want the above behavior, it's easy to duplicate, as I already  responded in my first post on the topic. Just make FooB return  dynamic_pointer_cast&lt;B&gt;( FooA() ) and remove the  enable_shared_from_this&lt;B&gt;<br />base (A needs to be made polymorphic, of course). <br /><br /><span style="color: #ff0000;" color="#ff0000">注意为了让dynamic_pointer_cast能工作，A必须具有虚函数，那么最简单的做法当然是令其析构函 数为虚函数（通常一个class如果希望被继承，析构函数就应该为虚函数）</span>。</div><img src ="http://www.cppblog.com/colorful/aggbug/179817.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colorful/" target="_blank">多彩人生</a> 2012-06-22 22:42 <a href="http://www.cppblog.com/colorful/archive/2012/06/22/179817.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>enable_shared_from_this（转载）</title><link>http://www.cppblog.com/colorful/archive/2012/06/22/179816.html</link><dc:creator>多彩人生</dc:creator><author>多彩人生</author><pubDate>Fri, 22 Jun 2012 14:41:00 GMT</pubDate><guid>http://www.cppblog.com/colorful/archive/2012/06/22/179816.html</guid><wfw:comment>http://www.cppblog.com/colorful/comments/179816.html</wfw:comment><comments>http://www.cppblog.com/colorful/archive/2012/06/22/179816.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colorful/comments/commentRss/179816.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colorful/services/trackbacks/179816.html</trackback:ping><description><![CDATA[<div><p>在 C++ 中需要自己来处理内存，稍微处理不当，就会存在非常郁闷的内存泄漏问题 </p> <p>&nbsp; </p> <p>还好，现在 C++ 中推出了强大的智能指针，即 smart_ptr ，本文先稍微介绍一下 smart_ptr ，然后具体说说 shared_ptr 和 weak_ptr ，特别是 enable_shared_from_this 和 shared_from_this </p> <p>&nbsp; </p> <p>除了标准库中的 auto_ptr 之外 </p> <p>在 boost 或者 tr1 中的 smart_ptr 主要是有下面几种 </p> <ul><li>scoped_ptr     </li><li>scoped_array     </li><li>shared_ptr     </li><li>shared_array     </li><li>intrusive_ptr     </li><li>weak_ptr </li></ul> <p>这些里面最难理解的是综合应用了 weak_ptr 和 shared_ptr 的 enable_shared_from_this 类，在该类中定了成员函数 shared_from_this() ，返回 shared_ptr&lt;T&gt; 。这个函数仅在 shared_ptr&lt;T&gt; 的构造函数被调用之后才能使用。原因是 enable_shared_from_this::weak_ptr 并不在构造函数中设置（此处的构造函数指的是类型 T 的构造函数），而是在 shared_ptr&lt;T&gt; 的构造函数中设置（此处的构造函数指的是类型 shared_ptr&lt;T&gt; 的构造函数）。 </p> <p>&nbsp; </p> <p>在下面的代码中： </p> <p>&nbsp; </p> <div> <div> <div>Cpp代码 </div> </div> <ol><li><span>#include&nbsp;&lt;iostream&gt; &nbsp;&nbsp;</span>     </li><li>&nbsp;&nbsp;     </li><li>#include&nbsp;&lt;string&gt; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>#include&nbsp;&lt;boost/shared_ptr.hpp&gt; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>#include&nbsp;&lt;boost/weak_ptr.hpp&gt; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>#include&nbsp;&lt;boost/enable_shared_from_this.hpp&gt; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>using&nbsp;namespace&nbsp;std; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>struct&nbsp;Ansible &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;:&nbsp;public&nbsp;boost::enable_shared_from_this&lt;Ansible&gt; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>{ &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;boost::shared_ptr&lt;Ansible&gt;&nbsp;get_shared() &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boost::shared_ptr&lt;Ansible&gt;&nbsp;r(this); &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;r; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;~Ansible() &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;"Destructor"&lt;&lt;endl; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>}; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>int&nbsp;main(int&nbsp;argc,char*&nbsp;argv[]) &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>{ &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;boost::shared_ptr&lt;Ansible&gt;&nbsp;a(new&nbsp;Ansible); &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;Ansible&amp;&nbsp;r&nbsp;=&nbsp;*a; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;//boost::shared_ptr&lt;Ansible&gt;&nbsp;b&nbsp;=&nbsp;r.get_shared(); &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;boost::shared_ptr&lt;Ansible&gt;&nbsp;b&nbsp;=&nbsp;r.shared_from_this(); &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;"Reference&nbsp;Number&nbsp;"&lt;&lt;a.use_count()&lt;&lt;"&nbsp;"&lt;&lt;b.use_count()&lt;&lt;endl; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0; &nbsp;&nbsp;     </li><li>&nbsp;&nbsp;     </li><li>}&nbsp;&nbsp; </li></ol> </div> <pre name="code">#include &lt;iostream&gt; #include &lt;string&gt; #include &lt;boost/shared_ptr.hpp&gt; #include &lt;boost/weak_ptr.hpp&gt; #include &lt;boost/enable_shared_from_this.hpp&gt; using namespace std; struct Ansible : public boost::enable_shared_from_this&lt;Ansible&gt; { boost::shared_ptr&lt;Ansible&gt; get_shared() { boost::shared_ptr&lt;Ansible&gt; r(this); return r; } ~Ansible() { cout&lt;&lt;"Destructor"&lt;&lt;endl; } }; int main(int argc,char* argv[]) { boost::shared_ptr&lt;Ansible&gt; a(new Ansible); Ansible&amp; r = *a; //boost::shared_ptr&lt;Ansible&gt; b = r.get_shared(); boost::shared_ptr&lt;Ansible&gt; b = r.shared_from_this(); cout&lt;&lt;"Reference Number "&lt;&lt;a.use_count()&lt;&lt;" "&lt;&lt;b.use_count()&lt;&lt;endl; return 0; }</pre> <p>&nbsp;</p> <p>若不使用 shared_from_this() 成员函数，则会输出 a 和 b 的 use_count() 都为 1 ，然后调用 2 次类型 Ansible 的析构函数，若添加了该成员函数，在 a 和 b 的 use_count() 输出为 2 ，只是调用一次 Ansible 的析构函数。原因是 enable_shared_from_this 里面在 shared_ptr&lt;T&gt; 的时候构造了一个 weak_ptr 类，而 weak_ptr 只是监视，不增加引用计数 </p> <p>&nbsp; </p> <p>（下面是转载： <a href="http://huyuguang1976.spaces.live.com/blog/cns%212A9E272E3C33AFF1%21185.entry">http://huyuguang1976.spaces.live.com/blog/cns!2A9E272E3C33AFF1!185.entry</a> ） </p> <p>所以如下代码是错误的： </p> <p>&nbsp; </p> <p>class D:public boost::enable_shared_from_this&lt;D&gt; </p> <p>{ </p> <p>public: </p> <p><span>&nbsp;&nbsp;&nbsp; D()</span> </p> <p><span>&nbsp;&nbsp;&nbsp; {</span> </p> <p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boost::shared_ptr&lt;D&gt; p=shared_from_this();</span> </p> <p><span>&nbsp;&nbsp;&nbsp; }</span> </p> <p>}; </p> <p>&nbsp; </p> <p>原因很简单，在 D 的构造函数中虽然可以保证 enable_shared_from_this&lt;D&gt; 的构造函数已经被调用，但正如前面所说， weak_ptr 还没有设置。 </p> <p>&nbsp; </p> <p>如下代码也是错误的： </p> <p>&nbsp; </p> <p>class D:public boost::enable_shared_from_this&lt;D&gt; </p> <p>{ </p> <p>public: </p> <p><span>&nbsp;&nbsp;&nbsp; void func()</span> </p> <p><span>&nbsp;&nbsp;&nbsp; {</span> </p> <p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boost::shared_ptr&lt;D&gt; p=shared_from_this();</span> </p> <p><span>&nbsp;&nbsp;&nbsp; }</span> </p> <p>}; </p> <p>&nbsp; </p> <p>void main() </p> <p>{ </p> <p><span>&nbsp;&nbsp;&nbsp; D d;</span> </p> <p><span>&nbsp;&nbsp;&nbsp; d.func();</span> </p> <p>} </p> <p>&nbsp; </p> <p>错误原因同上。 </p> <p>&nbsp; </p> <p>如下代码是正确的： </p> <p>&nbsp; </p> <p>void main() </p> <p>{ </p> <p><span>&nbsp;&nbsp;&nbsp; boost::shared_ptr&lt;D&gt; d(new D);</span> </p> <p><span>&nbsp;&nbsp;&nbsp; d-&gt;func();</span> </p> <p>} </p> <p>&nbsp; </p> <p>这里 boost::shared_ptr&lt;D&gt; d(new D) 实际上执行了 3 个动作：首先调用 enable_shared_from_this&lt;D&gt; 的构造函数；其次调用 D 的构造函数；最后调用 shared_ptr&lt;D&gt; 的构造函数。是第 3 个动作设置了 enable_shared_from_this&lt;D&gt; 的 weak_ptr ，而不是第 1 个动作。这个地方是很违背 c++ 常理和逻辑的，必须小心。 </p> <p>&nbsp; </p> <p>结论是，不要在构造函数中使用 shared_from_this ；其次，如果要使用 shared_ptr ，则应该在所有地方均使用，不能使用 D d 这种方式，也决不要传递裸指针。<br /><br /><br />另解：：：：：<br />struct X</p> <p>{</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boost::shared_ptr&lt;X&gt; getX()</p> <p>{</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boost::shared_ptr&lt;X&gt; r ;//????如何实现</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return r;</p> <p>}</p> <p>};</p> <p>&nbsp;</p> <p>要得到X的智能指针,只是在对象指针是受shared_ptr保护的基础上的,举例如下:</p> <p>void test_X()</p> <p>{</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p> <p>X x;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boost::shared_ptr&lt;X&gt; px = x.getX();//错误</p> <p>}</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p> <p>X* x = new X();</p> <p>boost::shared_ptr&lt;X&gt; px = x-&gt;getX();//错误</p> <p>}</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p> <p>boost::shared_ptr&lt;X&gt;&nbsp; x (new X());</p> <p>boost::shared_ptr&lt;X&gt; px = x-&gt;getX();//正确</p> <p>}</p> <p>}</p></div><img src ="http://www.cppblog.com/colorful/aggbug/179816.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colorful/" target="_blank">多彩人生</a> 2012-06-22 22:41 <a href="http://www.cppblog.com/colorful/archive/2012/06/22/179816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于boost::thread 的一件怪事</title><link>http://www.cppblog.com/colorful/archive/2012/05/14/174897.html</link><dc:creator>多彩人生</dc:creator><author>多彩人生</author><pubDate>Mon, 14 May 2012 13:50:00 GMT</pubDate><guid>http://www.cppblog.com/colorful/archive/2012/05/14/174897.html</guid><wfw:comment>http://www.cppblog.com/colorful/comments/174897.html</wfw:comment><comments>http://www.cppblog.com/colorful/archive/2012/05/14/174897.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/colorful/comments/commentRss/174897.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/colorful/services/trackbacks/174897.html</trackback:ping><description><![CDATA[本想测试printf的线程安全的,结果发现boost::thread的一件有趣的事,见代码<br /><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">cstdio</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br />#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">boost</span><span style="color: #000000; ">/</span><span style="color: #000000; ">thread.hpp</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br />#include&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">boost</span><span style="color: #000000; ">/</span><span style="color: #000000; ">bind.hpp</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; "><br /><br /></span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;fun1()<br />{<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;i</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;i</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">10</span><span style="color: #000000; ">;&nbsp;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">哈哈哈哈哈哈\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br />}<br /><br /></span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;fun2(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;count)<br />{<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">(</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;i</span><span style="color: #000000; ">=</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;i</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">count;&nbsp;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">呵呵呵呵呵呵\n</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br />}<br /><br /></span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;main()<br />{<br />&nbsp;&nbsp;&nbsp;boost::thread(fun1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;不以打印</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;boost::thread(fun2,&nbsp;</span><span style="color: #000000; ">10</span><span style="color: #000000; ">);&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;可以打印</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;boost::thread&nbsp;t(fun1);&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;可以打印</span><span style="color: #008000; "><br /></span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;getchar();<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">return</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;<br />}</span></div>不知什么原因，知道的可以告诉我吗<img src ="http://www.cppblog.com/colorful/aggbug/174897.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/colorful/" target="_blank">多彩人生</a> 2012-05-14 21:50 <a href="http://www.cppblog.com/colorful/archive/2012/05/14/174897.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>