<?xml version="1.0" encoding="gb2312"?>
<rss version="2.0">
<channel>
<title><![CDATA[零度の冰的博客]]></title>
        <image>
        <title>http://hi.baidu.com</title>
        <link>http://hi.baidu.com</link>
        <url>http://img.baidu.com/img/logo-hi.gif</url>
        </image>
<description><![CDATA[]]></description>
<link>http://hi.baidu.com/icexile</link>
<language>zh-cn</language>
<generator>www.baidu.com</generator>
<ttl>5</ttl>


<item>
        <title><![CDATA[超级无敌程序人生流程图]]></title>
        <link><![CDATA[http://hi.baidu.com/icexile/blog/item/ad2b91016dd5d40c1c9583fe.html]]></link>
        <description><![CDATA[
		
		<div ><p><img border="0" src="http://hiphotos.baidu.com/icexile/pic/item/59ba5606d7c219540308815d.jpg" width="730" height="532"></p></div> 
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/icexile/blog/category/%C9%FA%BB%EE">生活</a>&nbsp;<a href="http://hi.baidu.com/icexile/blog/item/ad2b91016dd5d40c1c9583fe.html#comment">查看评论</a>]]></description>
        <pubDate>2009年11月19日 星期四  上午 09:54</pubDate>
        <category><![CDATA[生活]]></category>
        <author><![CDATA[Icexile]]></author>
		<guid>http://hi.baidu.com/icexile/blog/item/ad2b91016dd5d40c1c9583fe.html</guid>
</item>

<item>
        <title><![CDATA[【转】Visual C++ 8 对象布局的奥秘：虚函数、多继承、虚拟继承]]></title>
        <link><![CDATA[http://hi.baidu.com/icexile/blog/item/a98c89358a613181a71e123c.html]]></link>
        <description><![CDATA[
		
		<p><div ><p>原文地址： <a href="http://www.cnblogs.com/neoragex2002/archive/2007/11/01/VC8_Object_Layout_Secret.html">http://www.cnblogs.com/neoragex2002/archive/2007/11/01/VC8_Object_Layout_Secret.html</a></p> <p>哈哈，从M$ Visual C++ Team的<a href="http://blogs.msdn.com/vcblog/archive/2007/05/17/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022.aspx">Andy Rich</a>那里又偷学到一招：VC8的隐含编译项<strong>/d1reportSingleClassLayout</strong>和<strong>/d1reportAllClassLayout</strong> 。看个复杂的例子吧(如下)，现在假设我们想知道Derived类的对象布局，怎么办? 在Project Properties-&gt;C++-&gt;Command Line-&gt;Additional Options里面加上<strong>/d1reportSingleClassLayoutDerived</strong>吧！</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>class CommonBase<br> {<br> &nbsp;&nbsp;&nbsp;  int co;<br> };</p> <p>class Base1: virtual public CommonBase<br> {<br> public:<br> &nbsp;&nbsp;&nbsp;  virtual void print1() {}<br> &nbsp;&nbsp;&nbsp;  virtual void print2() {}<br> private:<br> &nbsp;&nbsp;&nbsp;  int b1;<br> };</p> <p>class Base2: virtual public CommonBase<br> {<br> public:<br> &nbsp;&nbsp;&nbsp;  virtual void dump1() {}<br> &nbsp;&nbsp;&nbsp;  virtual void dump2() {}<br> private:<br> &nbsp;&nbsp;&nbsp;  int b2;<br> };</p> <p>class Derived: public Base1, public Base2<br> {<br> public:<br> &nbsp;&nbsp;&nbsp;  void print2() {}<br> &nbsp;&nbsp;&nbsp;  void dump2() {}<br> private:<br> &nbsp;&nbsp;&nbsp;  int d;<br> };</p> <p>int _tmain(int argc, _TCHAR* argv[])<br> {<br> &nbsp;&nbsp;&nbsp;  return 0;<br> }</p> </td> </tr> </tbody> </table> </div> <div class="codes"></div> <div class="codes">F5编译之，你会惊奇地发现，Output里面有如下字样：</div> <div class="codes"></div> <div class="codes"> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> 1 class Derived size(32):<br>  2&nbsp;&nbsp;&nbsp;  +---<br>  3&nbsp;&nbsp;&nbsp;  | +--- (base class Base1)<br>  4  0 | | {vfptr}<br>  5  4 | | {vbptr}<br>  6  8 | | b1<br>  7&nbsp;&nbsp;&nbsp;  | +---<br>  8&nbsp;&nbsp;&nbsp;  | +--- (base class Base2)<br>  9 12 | | {vfptr}<br> 10 16 | | {vbptr}<br> 11 20 | | b2<br> 12&nbsp;&nbsp;&nbsp;  | +---<br> 13 24 | d<br> 14&nbsp;&nbsp;&nbsp;  +---<br> 15&nbsp;&nbsp;&nbsp;  +--- (virtual base CommonBase)<br> 16 28 | co<br> 17&nbsp;&nbsp;&nbsp;  +---<br> 18<br> 19 Derived::$vftable@Base1@:<br> 20  0 | &amp;Base1::print1<br> 21  1 | &amp;Derived::print2<br> 22<br> 23 Derived::$vftable@Base2@:<br> 24  0 | &amp;Base2::dump1<br> 25  1 | &amp;Derived::dump2<br> 26<br> 27 Derived::$vbtable@Base1@:<br> 28  0 | -4<br> 29  1 | 24 (Derivedd(Base1+4)CommonBase)<br> 30<br> 31 Derived::$vbtable@Base2@:<br> 32  0 | -4<br> 33  1 | 12 (Derivedd(Base2+4)CommonBase)<br> 34<br> 35 Derived::print2 this adjustor: 0<br> 36 Derived::dump2 this adjustor: 12</td> </tr> </tbody> </table> </div> <div> </div> </div> <div class="codes"></div> <div class="codes">看到了吗? VC8居然输出了Derived对象的完整布局! 我们终于可以不必两眼一抹黑般的去peek/poke了....第1行表明，Derived对象总占用了32字节；其由三部分组成，分别是行3-行7、行 8-行12、行13、行28；其中前二者分别是基类Base1、Base2的布局，最后的行28为虚拟基类Common的布局。<br> <br> 以基类Base1部分为例，可发现其由一个虚函数表指针vftable和虚基表指针vbtable构成，先看Base1部分的vftable所指向的虚表$vftable@Base1(行19)，不难发现，其中的表项2已经被Derived::print2给override了；再来看Base2部分的 vftable所指向的虚表$vftable@Base2(行23)，可发现，同样的，Base2::dump2被Derived::dump2给 override了。这不明摆着就是虚函数机制嘛，heh~<br> <br> 值得注意的是，这个例子同时说明，多继承场合下，其实在单一对象中是存在多个this指针的....行35-36给出了如何将Derived的this指针校正为其基类子对象this指针的偏移量，也就是说，根据行36，假设有个Derived d，那么d.dump1()实际上应该理解成通过虚表$vftable@Base2对((Base2*) (((char*)&amp;d)+12))-&gt;dump1()的调用....即传递给所有Base2成员函数的this指针应该是 (Base2*)((char*)(&amp;d)+12)，这里可能我写得恐怖了点，意思到了就成....这不，普通继承、多继承、对象Slicing 的语义都在这个布局里面了，看仔细了哈~<br> <br> OK，多继承看完了，继续看虚拟基类是如何布局的。虚基Common在Derived的布局中，位于Derived本身数据成员之后的位置。Base1、 Base2中均保存了一个vbtable指针，其分别指向各自所使用的虚基表$vbtable@Base1和$vbtable@Base2，为什么要指向一个虚基表? 很简单，因为Base1、Base2有可能会同时继承多个不同的虚拟基类.....这充分体现了C++对象布局的复杂性....在每个虚基表中，保存了所继承的虚拟基类部分相对于子类部分vbtable指针的偏移值，以Base2为例，我们知道Base2的vbtable在Derived中的偏移值为 16(行10)，则根据$vbtable@Base2，虚基Common部分距离Base2 vbtable指针的偏移值为12,则有虚基Common在Derived中的总偏移值为16+12。与普通多继承同理，我们在调用非虚拟的虚基成员函数时，必须将Derived的this指针调整为指向虚基部分的this指针，只有这样才能成功地访问虚基自身的数据成员和虚基的虚拟函数(通过虚基自己的 vftable，为简单起见，上例中我就没弄那么复杂了，大家可以自己玩玩，明白如何举一反三即可)<br> <br> 看完了上述解释，是不是感觉比啃<a href="http://www.amazon.com/Inside-Object-Model-Stanley-Lippman/dp/0201834545">Inside C++ Object Model</a>来得更快更直观啊？呵呵</div></div></p> <a href="http://hi.baidu.com/icexile/blog/item/a98c89358a613181a71e123c.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/icexile/blog/category/visual%20c%2B%2B">visual c++</a>&nbsp;<a href="http://hi.baidu.com/icexile/blog/item/a98c89358a613181a71e123c.html#comment">查看评论</a>]]></description>
        <pubDate>2009年11月16日 星期一  下午 02:23</pubDate>
        <category><![CDATA[visual c++]]></category>
        <author><![CDATA[Icexile]]></author>
		<guid>http://hi.baidu.com/icexile/blog/item/a98c89358a613181a71e123c.html</guid>
</item>

<item>
        <title><![CDATA[【翻译】VC10中的C++0x新特性：decltype]]></title>
        <link><![CDATA[http://hi.baidu.com/icexile/blog/item/8be337b3feb3f1add8335a30.html]]></link>
        <description><![CDATA[
		
		<p><div ><p><a href="http://hi.baidu.com/icexile">零度の冰</a>翻译，<a href="http://blogs.msdn.com/vcblog/archive/2009/04/22/decltype-c-0x-features-in-vc10-part-3.aspx" target="_blank">原文地址在此</a>，转载请注明<a href="http://hi.baidu.com/icexile/blog/item/8be337b3feb3f1add8335a30.html">出处</a>。</p> <p>本系列<a href="http://hi.baidu.com/icexile/blog/item/a9836460f05fcbd58cb10dd0.html" target="_blank">第一部分</a>解释了<strong>lambda</strong>、<strong>auto</strong>和<strong>static_assert</strong>。<br> 本系列<a href="http://hi.baidu.com/icexile/blog/item/e8ad79344f43aa44241f1462.html" target="_blank">第二部分</a>解释了<strong>右值引用</strong>，以及由此产生的<strong>move语义</strong>和<strong>完美转发</strong>。</p> <p>下面将要讲述decltype，它使得完美转发函数可以有任意的类型的返回值。这给高度泛化的代码编写者提供了便利。</p> <h2>返回值类型的问题</h2> <p>C++98/03有一个有趣的遗漏点：给定一个像x * y这样的表达式，x和y的类型任意，没有方法能够取到x * y的类型。如果x是Watts类型，y是Second类型，那么x * y的类型假设是Joules。如果有一个函数模版是print(const T&amp; t)，那么可以调用print(x * y)，然后T将被推断为Joules。但是这项机制无法反过来运作：当我们写multiply(const A&amp; a, const B&amp; b)，你无法在保持泛化性的基础上写出返回值类型。即使multiply&lt;A, B&gt;()已经实例化了，编译器当然也知道x * y的类型，但是用户却得不到它。C++0x的decltype弥补了这个遗漏，它允许用户说“multiply()返回x * y的类型”（decltype是 declare type合成的）</p> <h2>decltype：模型</h2> <p>这里有一个完全泛化版的operator + ()的包装类的例子。这个Plus函数对象不是一个模板，但是它有一个成员函数模板，接受两个任意类型的参数，将它们相加并且返回结果，返回值也可能是任意的类型。</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type plus.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;iterator&gt;<br> #include &lt;ostream&gt;<br> #include &lt;string&gt;<br> #include &lt;utility&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>struct Plus {<br> &nbsp;&nbsp;&nbsp;  template &lt;typename T, typename U&gt;<br> &nbsp;&nbsp;&nbsp;  <strong>auto</strong> operator()(T&amp;&amp; t, U&amp;&amp; u) const<br> &nbsp;&nbsp;&nbsp;  <strong>-&gt; decltype(forward&lt;T&gt;(t) + forward&lt;U&gt;(u))</strong> {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return forward&lt;T&gt;(t) + forward&lt;U&gt;(u);<br> &nbsp;&nbsp;&nbsp;  }<br> };</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector&lt;int&gt; i;<br> &nbsp;&nbsp;&nbsp;  i.push_back(1);<br> &nbsp;&nbsp;&nbsp;  i.push_back(2);<br> &nbsp;&nbsp;&nbsp;  i.push_back(3);</p> <p>&nbsp;&nbsp;&nbsp;  vector&lt;int&gt; j;<br> &nbsp;&nbsp;&nbsp;  j.push_back(40);<br> &nbsp;&nbsp;&nbsp;  j.push_back(50);<br> &nbsp;&nbsp;&nbsp;  j.push_back(60);</p> <p>&nbsp;&nbsp;&nbsp;  vector&lt;int&gt; k;</p> <p>&nbsp;&nbsp;&nbsp;  vector&lt;string&gt; s;<br> &nbsp;&nbsp;&nbsp;  s.push_back(&quot;cut&quot;);<br> &nbsp;&nbsp;&nbsp;  s.push_back(&quot;flu&quot;);<br> &nbsp;&nbsp;&nbsp;  s.push_back(&quot;kit&quot;);</p> <p>&nbsp;&nbsp;&nbsp;  vector&lt;string&gt; t;<br> &nbsp;&nbsp;&nbsp;  t.push_back(&quot;e&quot;);<br> &nbsp;&nbsp;&nbsp;  t.push_back(&quot;ffy&quot;);<br> &nbsp;&nbsp;&nbsp;  t.push_back(&quot;tens&quot;);</p> <p>&nbsp;&nbsp;&nbsp;  vector&lt;string&gt; u;</p> <p>&nbsp;&nbsp;&nbsp;  transform(i.begin(), i.end(), j.begin(), back_inserter(k), Plus());<br> &nbsp;&nbsp;&nbsp;  transform(s.begin(), s.end(), t.begin(), back_inserter(u), Plus());</p> <p>&nbsp;&nbsp;&nbsp;  for_each(k.begin(), k.end(), [](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  for_each(u.begin(), u.end(), [](const string&amp; r) { cout &lt;&lt; r &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 plus.cpp<br> plus.cpp</p> <p>C:\Temp&gt;plus<br> 41 52 63<br> cute fluffy kittens</p> </td> </tr> </tbody> </table> </div> <p>将这个跟C++98/03&lt;functional&gt;中的std::plus&lt;T&gt;比较一下。因为std::plus&lt;T&gt;是个类模版，你使用时需要重复的键入元素的类型：比如传参时使用plus&lt;int&gt;()或是plus&lt;string&gt;。它的非模板化的调用运算符的形式是T operator ()(const T&amp; x, const T&amp; y) const，使得它在不考虑隐式类型转换的条件下无法处理两个不同类型的对象相加，更不用说三种不同类型了。（你可以给plus&lt;string&gt;()传入string型和const char *型，这样会导致字符串连接之前，在第二个参数上一个临时的string对象被创建出来。它的性能不是特别好。）最后，由于它返回类型是const T&amp;，它不能从C++0x的move语义上获得好处。Plus克服了上述所有的缺陷：Plus()没有重复声明元素的类型，可以处理“三种不同的类型”，它还使用了完美转发，从move语义上获得了好处。</p> <h2>延迟判断的返回值类型</h2> <p>现在，让我们再看一下模版化的函数调用运算符：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td>template &lt;typename T, typename U&gt;<br> <strong>auto</strong> operator()(T&amp;&amp; t, U&amp;&amp; u) const<br> <strong>-&gt; decltype(forward&lt;T&gt;(t) + forward&lt;U&gt;(u))</strong> {<br> &nbsp;&nbsp;&nbsp;  return forward&lt;T&gt;(t) + forward&lt;U&gt;(u);<br> }</td> </tr> </tbody> </table> </div> <p>这里，auto的含义和for(auto i = v.begin(); i != v.end(); ++i)不同，一个是说“让本对象的类型和初始化它的对象的类型相同”，一个是说“这个函数有一个延迟判断的返回值类型；在我声明了函数参数后，再告诉你返回值类型是什么。”这个形式和lambda表达式的返回值类型的显示声明形式是一样的，lambda表达式的返回值类型需要写在后面是因为“[]”需要顶头来表明一个lambda表达式的开始，而这里decltype需要靠后写是因为函数参数t和u需要首先声明，然后decltype才能看见它们并推断类型。（技术上讲，decltype(foward&lt;T&gt;(*static_cast&lt;T*&gt;(0)) + forward&lt;U&gt;(*static_cast&lt;U*&gt;(0)))）可以放在左边auto的位置上，但是这样显得非常250。</p> <p>给decltype传入和return语句一样的表达式保证了返回值类型在任何情况下都是正确的。（测验：为啥decltype(t + u)不对？）在这里重复写一遍是无法避免的，但是重复语句出现在相邻地点，因此没有危险性。</p> <h2>另一个例子</h2> <p>出于完整性考虑，这里给出一个处理“三个不同类型”的例子：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type mult.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;iterator&gt;<br> #include &lt;ostream&gt;<br> #include &lt;utility&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>struct Multiplies {<br> &nbsp;&nbsp;&nbsp;  template &lt;typename T, typename U&gt;<br> &nbsp;&nbsp;&nbsp;  auto operator()(T&amp;&amp; t, U&amp;&amp; u) const<br> &nbsp;&nbsp;&nbsp;  -&gt; decltype(forward&lt;T&gt;(t) * forward&lt;U&gt;(u)) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return forward&lt;T&gt;(t) * forward&lt;U&gt;(u);<br> &nbsp;&nbsp;&nbsp;  }<br> };</p> <p>class Watts {<br> public:<br> &nbsp;&nbsp;&nbsp;  explicit Watts(const int n) : m_n(n) { }<br> &nbsp;&nbsp;&nbsp;  int get() const { return m_n; }<br> private:<br> &nbsp;&nbsp;&nbsp;  int m_n;<br> };</p> <p>class Seconds {<br> public:<br> &nbsp;&nbsp;&nbsp;  explicit Seconds(const int n) : m_n(n) { }<br> &nbsp;&nbsp;&nbsp;  int get() const { return m_n; }<br> private:<br> &nbsp;&nbsp;&nbsp;  int m_n;<br> };</p> <p>class Joules {<br> public:<br> &nbsp;&nbsp;&nbsp;  explicit Joules(const int n) : m_n(n) { }<br> &nbsp;&nbsp;&nbsp;  int get() const { return m_n; }<br> private:<br> &nbsp;&nbsp;&nbsp;  int m_n;<br> };</p> <p>Joules operator*(const Watts&amp; w, const Seconds&amp; s) {<br> &nbsp;&nbsp;&nbsp;  return Joules(w.get() * s.get());<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector&lt;Watts&gt; w;<br> &nbsp;&nbsp;&nbsp;  w.push_back(Watts(2));<br> &nbsp;&nbsp;&nbsp;  w.push_back(Watts(3));<br> &nbsp;&nbsp;&nbsp;  w.push_back(Watts(4));</p> <p>&nbsp;&nbsp;&nbsp;  vector&lt;Seconds&gt; s;<br> &nbsp;&nbsp;&nbsp;  s.push_back(Seconds(5));<br> &nbsp;&nbsp;&nbsp;  s.push_back(Seconds(6));<br> &nbsp;&nbsp;&nbsp;  s.push_back(Seconds(7));</p> <p>&nbsp;&nbsp;&nbsp;  vector&lt;Joules&gt; j;</p> <p>&nbsp;&nbsp;&nbsp;  transform(w.begin(), w.end(), s.begin(), back_inserter(j), Multiplies());</p> <p>&nbsp;&nbsp;&nbsp;  for_each(j.begin(), j.end(), [](const Joules&amp; r) { cout &lt;&lt; r.get() &lt;&lt; endl; });<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 mult.cpp<br> mult.cpp</p> <p>C:\Temp&gt;mult<br> 10<br> 18<br> 28</p> </td> </tr> </tbody> </table> </div> <p>你可能会问，“这种泛化能力真的都非常必要吗？”答案是yes，非常yes。前面已经看到了decltype和完美转发使得算术函数对象变得更加易于使用（通过避免重复声明元素类型），更加灵活（通过处理不同的参数和返回值类型），更加高效（通过move语义）。更加重要的是，完美转发和decltype允许你写出更加简洁的代码。</p> <h2>高级规则</h2> <p>decltype由一坨规则驱动。但是，如果你按照上面的样式做，那它会工作的很好。</p> <p>虽然大多数 decltype 应用遵循上面介绍的模式，但 decltype 还可以用于其他环境。在那些情况下，你就用到了 decltype 的高级模式，你应该全面地阅读那些规则，它们在 C++0x 工作草案 <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2857.pdf" target="_blank">N2857</a>，7.1.6.2 [dcl.type.simple]/4 中被给出。</p> <h2>等等，还有一些话要说</h2> <p>decltype 是第五个且是最后一个添加到VC10中的 C++0x 核心语言特性VC10 CTP中没有，但VC10 Bata 1中有。而且 VC10 Beta 1 中还有很多 C++0x 标准库特性，我会在后续文章中介绍它们。<br> <br> Stephan T. Lavavej<br> Visual C++ Libraries Developer<br></p></div></p> <a href="http://hi.baidu.com/icexile/blog/item/8be337b3feb3f1add8335a30.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/icexile/blog/category/visual%20c%2B%2B">visual c++</a>&nbsp;<a href="http://hi.baidu.com/icexile/blog/item/8be337b3feb3f1add8335a30.html#comment">查看评论</a>]]></description>
        <pubDate>2009年11月16日 星期一  下午 02:18</pubDate>
        <category><![CDATA[visual c++]]></category>
        <author><![CDATA[Icexile]]></author>
		<guid>http://hi.baidu.com/icexile/blog/item/8be337b3feb3f1add8335a30.html</guid>
</item>

<item>
        <title><![CDATA[【翻译】VC10中的C++0x新特性：右值引用(rvalue references) （3）]]></title>
        <link><![CDATA[http://hi.baidu.com/icexile/blog/item/82b8084eeab430c0d0c86a0c.html]]></link>
        <description><![CDATA[
		
		<p><div ><p><a href="http://hi.baidu.com/icexile">零度の冰</a>翻译，<a href="http://blogs.msdn.com/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx" target="_blank">原文地址在此</a>，转载请注明<a href="http://hi.baidu.com/icexile/blog/item/82b8084eeab430c0d0c86a0c.html">出处</a>。</p> <p>接<a href="http://hi.baidu.com/icexile/blog/item/87f7ee88339f229ea5c27239.html" target="_blank">【翻译】VC10中的C++0x新特性：右值引用(rvalue references) （2）</a></p> <h2>右值引用：模板参数推导和引用折叠</h2> <p>右值引用和模板以一种特别的方式相互作用。下面是一个示例：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type collapse.cpp<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;string&gt;<br> using namespace std;</p> <p>template &lt;typename T&gt; struct Name;</p> <p>template &lt;&gt; struct Name&lt;string&gt; {<br> &nbsp;&nbsp;&nbsp;  static const char * get() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return &quot;string&quot;;<br> &nbsp;&nbsp;&nbsp;  }<br> };</p> <p>template &lt;&gt; struct Name&lt;const string&gt; {<br> &nbsp;&nbsp;&nbsp;  static const char * get() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return &quot;const string&quot;;<br> &nbsp;&nbsp;&nbsp;  }<br> };</p> <p>template &lt;&gt; struct Name&lt;string&amp;&gt; {<br> &nbsp;&nbsp;&nbsp;  static const char * get() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return &quot;string&amp;&quot;;<br> &nbsp;&nbsp;&nbsp;  }<br> };</p> <p>template &lt;&gt; struct Name&lt;const string&amp;&gt; {<br> &nbsp;&nbsp;&nbsp;  static const char * get() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return &quot;const string&amp;&quot;;<br> &nbsp;&nbsp;&nbsp;  }<br> };</p> <p>template &lt;&gt; struct Name&lt;string&amp;&amp;&gt; {<br> &nbsp;&nbsp;&nbsp;  static const char * get() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return &quot;string&amp;&amp;&quot;;<br> &nbsp;&nbsp;&nbsp;  }<br> };</p> <p>template &lt;&gt; struct Name&lt;const string&amp;&amp;&gt; {<br> &nbsp;&nbsp;&nbsp;  static const char * get() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return &quot;const string&amp;&amp;&quot;;<br> &nbsp;&nbsp;&nbsp;  }<br> };</p> <p>template &lt;typename T&gt; void quark(T&amp;&amp; t) {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;t: &quot; &lt;&lt; t &lt;&lt; endl;<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;T: &quot; &lt;&lt; Name&lt;T&gt;::get() &lt;&lt; endl;<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;T&amp;&amp;: &quot; &lt;&lt; Name&lt;T&amp;&amp;&gt;::get() &lt;&lt; endl;<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }</p> <p>string strange() {<br> &nbsp;&nbsp;&nbsp;  return &quot;strange()&quot;;<br> }</p> <p>const string charm() {<br> &nbsp;&nbsp;&nbsp;  return &quot;charm()&quot;;<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  string up(&quot;up&quot;);<br> &nbsp;&nbsp;&nbsp;  const string down(&quot;down&quot;);</p> <p>&nbsp;&nbsp;&nbsp;  quark(up);<br> &nbsp;&nbsp;&nbsp;  quark(down);<br> &nbsp;&nbsp;&nbsp;  quark(strange());<br> &nbsp;&nbsp;&nbsp;  quark(charm());<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 collapse.cpp<br> collapse.cpp</p> <p>C:\Temp&gt;collapse<br> t: up<br> T: string&amp;<br> T&amp;&amp;: string&amp;</p> <p>t: down<br> T: const string&amp;<br> T&amp;&amp;: const string&amp;</p> <p>t: strange()<br> T: string<br> T&amp;&amp;: string&amp;&amp;</p> <p>t: charm()<br> T: const string<br> T&amp;&amp;: const string&amp;&amp;</p> </td> </tr> </tbody> </table> </div> <p>这里Name的显式特化帮助我们打印出类型的名字。</p> <p>当我们调用quark(up)，编译器先进行模板类型参数的推导。quark是一个函数模板，其模板参数是T，但是我们调用它时并没有显式的给出类型参数（像quark&lt;X&gt;(up)），而是通过比较函数的形参Type&amp;&amp;和实参（一个string类型的左值）来推导出模板的类型参数。</p> <p>C++0x 会转换函数实参的类型和形参的类型，然后再把它们匹配在一起。</p> <p>首先，编译器转换函数实参类型。一条<strong>特殊的规则</strong>(N2798 14.8.2.1 [temp.deduct.call]/3)被激活了：当一个函数形参类型是T&amp;&amp;（T是一个模板参数），函数实参又是一个A类型的左值，那么使用A&amp;来进行模板参数推导。（这条特殊的规则不适用于函数实参为T&amp;或是const T&amp;的情况，它们会按照C++98/03规则推导。此特殊规则也不适用于const T&amp;&amp;。）在quark(up)这种情况，适用特殊规则，实参类型被转换为string&amp;。</p> <p>接着，编译器转换函数形参类型，C++98/03和C++0x都会忽略引用（C++0x即忽略左值引用，又忽略右值引用），在所有四次调用时，都意味着我们将T&amp;&amp;转换成为了T。</p> <p>因此，我们推导出T为函数实参类型。这就是为啥quark(up)输出了“T::string&amp;”，quark(down)输出了“T::const string&amp;”，up和down都是左值，因此它们激活了那条特殊规则。strange()和charm()是右值，因此它们使用正常的规则，这就是为啥quark(strange())输出“T::string”，quark(charm())输出“T::const string”了。</p> <p>模板参数推导之后，编译器开始替换操作。编译器把每个出现的T都替换成推导出的类型，在quark(strange())中，T是string，因此T&amp;&amp;是string&amp;&amp;。类似的，在quark(charm())中，T是const string，因此T&amp;&amp;是const string&amp;&amp;。但是，quark(up)和quark(down)激活了另一条特殊规则。</p> <p>在quark(up)中，T是string&amp;，T&amp;&amp;的替换操作导致了结果string&amp; &amp;&amp;。在C++0x中引用的引用将会退化，并且引用退化的规则是“左值的引用具有传染性”，X&amp; &amp;，X&amp; &amp;&amp;，和X&amp;&amp; &amp;，都退化为X&amp;，只有X&amp;&amp; &amp;&amp;退化为了X&amp;&amp;。因此，string&amp; &amp;&amp;退化到string&amp;。在模板函数中，那些看起来像右值引用的参数，其实并不一定是。quark(up)实例化为了quark&lt;string&amp;&gt;()。在这个实例中，<strong>参数T&amp;&amp;变为了string&amp;</strong>。我们通过Name&lt;T&amp;&amp;&gt;::get()已经观察到了这一点。类似的，quark(down)实例化为了quark&lt;const string&amp;&gt;()，参数T&amp;&amp;变为了const string&amp;。在C++98/03中，你可能已经习惯了常量性隐藏于模板参数中了（一个接受参数T&amp;的函数模板可以使用const Foo对象去调用；使T&amp;看起来变为了const Foo&amp;），在C++0x中，左值性也可以隐藏在函数模板参数中。</p> <p>好的，那么我们要问这两条特殊规则给我们带来了什么？在quark()中，T&amp;&amp;有着和实参同样的左右值和常量属性，因此可以用右值引用这种保留实参左右值和常量性的特点实现完美转发。</p> <h2>完美转发：std::forward()和std::identity如何工作</h2> <p>让我们再次看一下outer()：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td>template &lt;typename T1, typename T2&gt; void outer(T1&amp;&amp; t1, T2&amp;&amp; t2) {<br> &nbsp;&nbsp;&nbsp;  inner(<strong>Forward&lt;T1&gt;</strong>(t1), <strong>Forward&lt;T2&gt;</strong>(t2));<br> }</td> </tr> </tbody> </table> </div> <p>现在我们明白了为什么outer()接受参数类型为T1&amp;&amp;和T2&amp;&amp;了。这样outer()实参的所有信息都会被保留。但是为什么它要调用Forward&lt;T1&gt;()和Forward&lt;T2&gt;()？回想一下，所有具名左值引用和具名右值引用都是左值。如果outer()调用inner(t1, t2)，那么inner()接收到的参数将总是左值，转发就不完美了。</p> <p>幸运的是，匿名的左值引用是左值，而匿名的右值引用是右值。因此，为了将t1和t2转发给inner()，我们需要使用辅助函数保存它们的类型信息但是移除它们的名字。这就是std::forward()的功能：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>template &lt;typename T&gt; struct Identity {<br> &nbsp;&nbsp;&nbsp;  typedef T type;<br> };</p> <p>template &lt;typename T&gt; T&amp;&amp; Forward(typename Identity&lt;T&gt;::type&amp;&amp; t) {<br> &nbsp;&nbsp;&nbsp;  return t;<br> }</p> </td> </tr> </tbody> </table> </div> <p>当我们调用Forward&lt;T1&gt;(t1)时，Identity并没有修改T1的类型（我们一会儿将看到他干了什么）。因此Forward&lt;T1&gt;()接受参数为T1&amp;&amp;并且返回T1&amp;&amp;。这保证了t1的类型无改变（不管它是什么：string&amp;，const string&amp;，string&amp;&amp;，const string&amp;&amp;）而又移除了它的名字。inner()将收到Forward&lt;T1&gt;(t1)，它和t1具有同样的左右值/常量属性。这就是完美转发的工作原理。</p> <p>你可能会问如果把Forward&lt;T1&gt;(t1)写成Forward&lt;T1&amp;&amp;&gt;(t1)的话会发生什么（这是个经常出现的错误，因为outer的参数就是T1&amp;&amp;）。幸运的是，这样不会导致什么坏的结果。因为Forward&lt;T1&amp;&amp;&gt;()将接受和返回T1&amp;&amp; &amp;&amp;类型，它会退化成T1&amp;&amp;。因此Forward&lt;T1&gt;(t1)和Forward&lt;T1&amp;&amp;&gt;(t1)是一样的，但是前面的形式更短，因此更加流行。</p> <p>Identity干了什么？为什么下面的形式无法工作呢？</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td>template &lt;typename T&gt; T&amp;&amp; Forward(<strong>T&amp;&amp; t</strong>) { <strong>// BROKEN<br></strong>&nbsp;&nbsp;&nbsp;  return t;<br> }</td> </tr> </tbody> </table> </div> <p>如果像上面这样实现Forward()，那么就可以不显示的指定模板参数而调用它，模板类型参数推导机制就会插进来，而我们之前已经看到了在T&amp;&amp;上面推导会发生：当调用它的实参是左值的时候，T&amp;&amp;将会变成左值。而我们要实现的是在outer()中，具名的t1和t2是左值的时候，我们也要将其改为右值转发。使用上面的BROKEN实现，无法完成这个功能，T&amp;&amp;有可能被编译器推导为左值。因此我们使用Identity来阻止编译器的模板参数推导机制的介入。经常使用模板的程序员应该对这个很熟悉了，因为这个在C++98/03和C++0x中都完成同样的工作：typename Identity&lt;T&gt;::type中的那对冒号就像块铅板一样，编译器的模板类型推导无法穿越到它的左边。（解释其原理又是另外的话题了）</p> <h2>move语义：std::move()是如何工作的</h2> <p>现在我们已经了解了模版类型推导中的特殊规则，以及引用退化，让我们再看一下std::move()：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>template &lt;typename T&gt; struct RemoveReference {<br> &nbsp;&nbsp;&nbsp;&nbsp;  typedef T type;<br> };</p> <p>template &lt;typename T&gt; struct RemoveReference&lt;T&amp;&gt; {<br> &nbsp;&nbsp;&nbsp;&nbsp;  typedef T type;<br> };</p> <p>template &lt;typename T&gt; struct RemoveReference&lt;T&amp;&amp;&gt; {<br> &nbsp;&nbsp;&nbsp;&nbsp;  typedef T type;<br> };</p> <p>template &lt;typename T&gt; typename RemoveReference&lt;T&gt;::type&amp;&amp; Move(T&amp;&amp; t) {<br> &nbsp;&nbsp;&nbsp;  return t;<br> }</p> </td> </tr> </tbody> </table> </div> <p>RemoveReference的实现机制和C++0x头文件&lt;type_traits&gt;中的std::remove_reference一样。例如：RemoveReference&lt;string&gt;::type，RemoveReference&lt;string&amp;&gt;::type，和RemoveReference&lt;string&amp;&amp;&gt;::type都是string。</p> <p>同样的，Move()和C++0x头文件&lt;utility&gt;的实现机制一样。</p> <ul> <li>当Move()被一个左值string调用，T被推断为string&amp;，因此Move()接受到string&amp;类型的参数（引用退化过以后），经过RemoveReference，返回值为string&amp;&amp;。</li> <li>当Move()被一个左值const string调用，T被推断为const string&amp;，因此Move()接受到const string&amp;类型的参数（引用退化过以后），经过RemoveReference，返回值为const string&amp;&amp;。</li> <li>当Move()被一个右值string调用，T被推断为string，因此Move()接受到string&amp;&amp;类型的参数，经过RemoveReference，返回值为string&amp;&amp;。</li> <li>当Move()被一个右值const string调用，T被推断为const string，因此Move()接受到const string&amp;&amp;类型的参数，经过RemoveReference，返回值为const string&amp;&amp;。</li> </ul> <p>这就是std::move()保持类型的常量属性的同时，将左值转换为右值返回的原理。</p> <h2>回顾 </h2> <p>如果你想了解更多的右值引用的信息，你可以阅读它们的提案。要注意的是现在的情况可能已经跟提案不太一样了，右值引用已经被纳入了C++0x Working Paper，并得到了持续的改进。提案中有的部分已经过时了，有的不再正确，或者没有被C++0x标准采纳。但它仍然具有很大的参考价值。</p> <p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm">N1377</a>，<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm">N1385</a>，和<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html">N1690</a>是右值引用主要的草案。<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html" target="_blank">N2118</a>包含了草案的被纳入C++0x Working Paper之前的最终版本。<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1784.htm" target="_blank">N1784</a>，<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1821.htm" target="_blank">N1821</a>，<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2377.htm" target="_blank">N2377</a>，和<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm" target="_blank">N2439</a>记录了将move语义扩展到*this的进化过程，它已经成为了C++0x标准，但VC10尚未实现它。</p> <h2>展望</h2> <p><a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2812.html" target="_blank">N2812</a>“右值引用的一个安全问题（以及如何解决它）”提出了对初始化规则的修改：禁止右值引用绑定到左值上。这不会影响到move语义和完美转发，所以不会导致你刚学到的新技术的失效（但是它会导致std::move()和std::forward()实现方式的改变）</p> Stephan T. Lavavej<br> Visual C++ Libraries Developer<br></div></p> <a href="http://hi.baidu.com/icexile/blog/item/82b8084eeab430c0d0c86a0c.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/icexile/blog/category/visual%20c%2B%2B">visual c++</a>&nbsp;<a href="http://hi.baidu.com/icexile/blog/item/82b8084eeab430c0d0c86a0c.html#comment">查看评论</a>]]></description>
        <pubDate>2009年11月11日 星期三  下午 06:30</pubDate>
        <category><![CDATA[visual c++]]></category>
        <author><![CDATA[Icexile]]></author>
		<guid>http://hi.baidu.com/icexile/blog/item/82b8084eeab430c0d0c86a0c.html</guid>
</item>

<item>
        <title><![CDATA[【翻译】VC10中的C++0x新特性：右值引用(rvalue references) （2）]]></title>
        <link><![CDATA[http://hi.baidu.com/icexile/blog/item/87f7ee88339f229ea5c27239.html]]></link>
        <description><![CDATA[
		
		<p><div ><p><a href="http://hi.baidu.com/icexile">零度の冰</a>翻译，<a href="http://blogs.msdn.com/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx" target="_blank">原文地址在此</a>，转载请注明<a href="http://hi.baidu.com/icexile/blog/item/87f7ee88339f229ea5c27239.html">出处</a>。</p> <p>接<a href="http://hi.baidu.com/icexile/blog/item/e8ad79344f43aa44241f1462.html">【翻译】VC10中的C++0x新特性：右值引用(rvalue references) （1）</a></p> <h2>move语义：移动左值</h2> <p>现在，如果你喜欢使用赋值运算符来实现拷贝构造函数的话，将会怎么样？你可能会尝试使用你的move赋值运算符去实现move构造函数。这是可能的，但是你需要小心，下面就是一种<strong>错误</strong>的做法：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type unified_wrong.cpp<br> #include &lt;stddef.h&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> using namespace std;</p> <p>class remote_integer {<br> public:<br> &nbsp;&nbsp;&nbsp;  remote_integer() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Default constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  explicit remote_integer(const int n) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Unary constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = new int(n);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer(const remote_integer&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Copy constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  *this = other;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>#ifdef MOVABLE<br> &nbsp;&nbsp;&nbsp;  remote_integer(remote_integer&amp;&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;MOVE CONSTRUCTOR.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <strong>*this = other; // WRONG</strong><br> &nbsp;&nbsp;&nbsp;  }<br> #endif // #ifdef MOVABLE</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer&amp; operator=(const remote_integer&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Copy assignment operator.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (this != &amp;other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (other.m_p) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = new int(*other.m_p);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } else {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return *this;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>#ifdef MOVABLE<br> &nbsp;&nbsp;&nbsp;  remote_integer&amp; operator=(remote_integer&amp;&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;MOVE ASSIGNMENT OPERATOR.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (this != &amp;other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = other.m_p;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  other.m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return *this;<br> &nbsp;&nbsp;&nbsp;  }<br> #endif // #ifdef MOVABLE</p> <p>&nbsp;&nbsp;&nbsp;  ~remote_integer() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Destructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int get() const {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return m_p ? *m_p : 0;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>private:<br> &nbsp;&nbsp;&nbsp;  int * m_p;<br> };</p> <p>remote_integer frumple(const int n) {<br> &nbsp;&nbsp;&nbsp;  if (n == 1729) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return remote_integer(1729);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer ret(n * n);</p> <p>&nbsp;&nbsp;&nbsp;  return ret;<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  remote_integer x = frumple(5);</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; x.get() &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer y = frumple(1729);</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; y.get() &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 /O2 unified_wrong.cpp<br> unified_wrong.cpp</p> <p>C:\Temp&gt;unified_wrong<br> Unary constructor.<br> Copy constructor.<br> Copy assignment operator.<br> Destructor.<br> 25<br> Unary constructor.<br> 1729<br> Destructor.<br> Destructor.</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 /O2 /DMOVABLE unified_wrong.cpp<br> unified_wrong.cpp</p> <p>C:\Temp&gt;unified_wrong<br> Unary constructor.<br> MOVE CONSTRUCTOR.<br> <strong>Copy assignment operator.<br></strong>Destructor.<br> 25<br> Unary constructor.<br> 1729<br> Destructor.<br> Destructor.</p> </td> </tr> </tbody> </table> </div> <p>（编译器在这里实施了RVO优化，但没有NRVO。我上面已经提到，有些拷贝构造函数的调用被RVO和NRVO优化掉了，但编译器不是每次都能实施这种优化，move构造函数优化掉了剩余的情况）</p> <p>在move构造函数里标记WRONG的那一行调用了copy赋值运算符，而不是move赋值运算符！这样也能正常编译运行，但move构造函数的目的没有达到。</p> <p>为啥会这样呢？从C++98/03里回想一下，具名的左值引用是左值（int&amp; r = *p;，r是左值）匿名的左值引用还是左值（vector&lt;int&gt;v(10, 1729)，调用v[0]返回int&amp;，这是个匿名左值引用，它的地址是可以获取的）。右值引用的行为就不同了：</p> <ul> <li>具名的右值引用是左值。</li> <li>匿名的右值引用是右值。</li> </ul> <p>具名的左值引用可以被重复的使用，也可以在上面施加多次操作。如果让具名左值引用成为右值的话，那施加在其身上的第一个操作可能就会把它的资源偷走，导致后续的操作失效。偷取是不应该影响其它操作的，因此具名左值引用应该是左值。另一方面，匿名的右值引用不会被重复使用，因此它可以保持自己的右值属性。</p> <p>如果你真的想用move赋值运算符实现move构造函数，你需要一种把左值看作是右值的能力。C++0x头文件&lt;utility&gt;中的std::move()赋予你了这种能力，VC10会包含它。（译注：原文写作时，std::move()尚未包含进VC10，因此作者接着给出了std::move的实现）</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type unified_right.cpp<br> #include &lt;stddef.h&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> using namespace std;</p> <p><strong>template &lt;typename T&gt; struct RemoveReference {<br> &nbsp;&nbsp;&nbsp;&nbsp;  typedef T type;<br> };</strong></p> <p><strong>template &lt;typename T&gt; struct RemoveReference&lt;T&amp;&gt; {<br> &nbsp;&nbsp;&nbsp;&nbsp;  typedef T type;<br> };</strong></p> <p><strong>template &lt;typename T&gt; struct RemoveReference&lt;T&amp;&amp;&gt; {<br> &nbsp;&nbsp;&nbsp;&nbsp;  typedef T type;<br> };</strong></p> <p><strong>template &lt;typename T&gt; typename RemoveReference&lt;T&gt;::type&amp;&amp; Move(T&amp;&amp; t) {<br> &nbsp;&nbsp;&nbsp;  return t;<br> }</strong></p> <p>class remote_integer {<br> public:<br> &nbsp;&nbsp;&nbsp;  remote_integer() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Default constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  explicit remote_integer(const int n) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Unary constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = new int(n);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer(const remote_integer&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Copy constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  *this = other;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>#ifdef MOVABLE<br> &nbsp;&nbsp;&nbsp;  remote_integer(remote_integer&amp;&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;MOVE CONSTRUCTOR.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <strong>*this = Move(other); // RIGHT<br></strong>&nbsp;&nbsp;&nbsp;  }<br> #endif // #ifdef MOVABLE</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer&amp; operator=(const remote_integer&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Copy assignment operator.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (this != &amp;other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (other.m_p) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = new int(*other.m_p);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } else {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return *this;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>#ifdef MOVABLE<br> &nbsp;&nbsp;&nbsp;  remote_integer&amp; operator=(remote_integer&amp;&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;MOVE ASSIGNMENT OPERATOR.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (this != &amp;other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = other.m_p;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  other.m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return *this;<br> &nbsp;&nbsp;&nbsp;  }<br> #endif // #ifdef MOVABLE</p> <p>&nbsp;&nbsp;&nbsp;  ~remote_integer() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Destructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int get() const {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return m_p ? *m_p : 0;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>private:<br> &nbsp;&nbsp;&nbsp;  int * m_p;<br> };</p> <p>remote_integer frumple(const int n) {<br> &nbsp;&nbsp;&nbsp;  if (n == 1729) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return remote_integer(1729);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer ret(n * n);</p> <p>&nbsp;&nbsp;&nbsp;  return ret;<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  remote_integer x = frumple(5);</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; x.get() &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer y = frumple(1729);</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; y.get() &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 /O2 /DMOVABLE unified_right.cpp<br> unified_right.cpp</p> <p>C:\Temp&gt;unified_right<br> Unary constructor.<br> MOVE CONSTRUCTOR.<br> <strong>MOVE ASSIGNMENT OPERATOR.</strong><br> Destructor.<br> 25<br> Unary constructor.<br> 1729<br> Destructor.<br> Destructor.</p> </td> </tr> </tbody> </table> </div> <p>（我将会把我实现的Move()作为std::move()来讲，因为它们实现原理是一样的）std::move()是如何工作的呢？目前，我只能告诉你这是个“牛×的魔法”。（一会儿我会详细解释，它并不复杂，但是它包括模版参数推导和引用退化（译注：引用的引用 = 引用），后面讲完美转发的时候还会遇到这俩东西）我可以用一个具体的例子来略过讲述这个魔法：给一个string类型的左值，就像上面代码中的up，std::move(up)调用的是 string&amp;&amp; std::move(string&amp;)，它返回的是个匿名的右值引用，而匿名的右值引用是右值。给定一个像上面代码中的strange()这样的右值string类型，std::move(strange())调用的是 string&amp;&amp; std::move(string&amp;&amp;)，又一次，返回值是匿名右值引用，还是右值。</p> <p>std::move在其它地方也非常有用。任何时候只要你拥有一个左值，而你已经不再需要它了（它将要被销毁或者被赋予别的值），你就可以使用std::move(左值表达式)来激活move语义。</p> <h2>move语义：可移动的数据成员</h2> <p>C++0x的标准类(vector、string、regex等)都有move构造函数和move赋值运算符，并且我们已经了解了如何在自己的类中实现它们去手动的管理资源。但是当我们的类中有可move的数据成员（vector、string、regex）时咋弄？编译器不会为我们自动生成move构造函数和move赋值运算符。因此我们需要自己实现它们。幸运的是，有了std::move()，这就非常简单了：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type point.cpp<br> #include &lt;stddef.h&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> using namespace std;</p> <p>template &lt;typename T&gt; struct RemoveReference {<br> &nbsp;&nbsp;&nbsp;&nbsp;  typedef T type;<br> };</p> <p>template &lt;typename T&gt; struct RemoveReference&lt;T&amp;&gt; {<br> &nbsp;&nbsp;&nbsp;&nbsp;  typedef T type;<br> };</p> <p>template &lt;typename T&gt; struct RemoveReference&lt;T&amp;&amp;&gt; {<br> &nbsp;&nbsp;&nbsp;&nbsp;  typedef T type;<br> };</p> <p>template &lt;typename T&gt; typename RemoveReference&lt;T&gt;::type&amp;&amp; Move(T&amp;&amp; t) {<br> &nbsp;&nbsp;&nbsp;  return t;<br> }</p> <p>class remote_integer {<br> public:<br> &nbsp;&nbsp;&nbsp;  remote_integer() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Default constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  explicit remote_integer(const int n) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Unary constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = new int(n);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer(const remote_integer&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Copy constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (other.m_p) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = new int(*other.m_p);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } else {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer(remote_integer&amp;&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;MOVE CONSTRUCTOR.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = other.m_p;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  other.m_p = NULL;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer&amp; operator=(const remote_integer&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Copy assignment operator.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (this != &amp;other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (other.m_p) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = new int(*other.m_p);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } else {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return *this;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer&amp; operator=(remote_integer&amp;&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;MOVE ASSIGNMENT OPERATOR.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (this != &amp;other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = other.m_p;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  other.m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return *this;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  ~remote_integer() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Destructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int get() const {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return m_p ? *m_p : 0;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>private:<br> &nbsp;&nbsp;&nbsp;  int * m_p;<br> };</p> <p>class remote_point {<br> public:<br> &nbsp;&nbsp;&nbsp;  remote_point(const int x_arg, const int y_arg)<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  : m_x(x_arg), m_y(y_arg) { }</p> <p><strong>&nbsp;&nbsp;&nbsp;  remote_point(remote_point&amp;&amp; other)<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  : m_x(Move(other.m_x)),<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_y(Move(other.m_y)) { }</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;  remote_point&amp; operator=(remote_point&amp;&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_x = Move(other.m_x);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_y = Move(other.m_y);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return *this;<br> &nbsp;&nbsp;&nbsp;  }</strong></p> <p>&nbsp;&nbsp;&nbsp;  int x() const { return m_x.get(); }<br> &nbsp;&nbsp;&nbsp;  int y() const { return m_y.get(); }</p> <p>private:<br> &nbsp;&nbsp;&nbsp;  remote_integer m_x;<br> &nbsp;&nbsp;&nbsp;  remote_integer m_y;<br> };</p> <p>remote_point five_by_five() {<br> &nbsp;&nbsp;&nbsp;  return remote_point(5, 5);<br> }</p> <p>remote_point taxicab(const int n) {<br> &nbsp;&nbsp;&nbsp;  if (n == 0) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return remote_point(1, 1728);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  remote_point ret(729, 1000);</p> <p>&nbsp;&nbsp;&nbsp;  return ret;<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  remote_point p = taxicab(43112609);</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;(&quot; &lt;&lt; p.x() &lt;&lt; &quot;, &quot; &lt;&lt; p.y() &lt;&lt; &quot;)&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  p = five_by_five();</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;(&quot; &lt;&lt; p.x() &lt;&lt; &quot;, &quot; &lt;&lt; p.y() &lt;&lt; &quot;)&quot; &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 /O2 point.cpp<br> point.cpp</p> <p>C:\Temp&gt;point<br> Unary constructor.<br> Unary constructor.<br> <strong>MOVE CONSTRUCTOR.<br> MOVE CONSTRUCTOR.</strong><br> Destructor.<br> Destructor.<br> (729, 1000)<br> Unary constructor.<br> Unary constructor.<br> <strong>MOVE ASSIGNMENT OPERATOR.<br> MOVE ASSIGNMENT OPERATOR.<br></strong>Destructor.<br> Destructor.<br> (5, 5)<br> Destructor.<br> Destructor.</p> </td> </tr> </tbody> </table> </div> <p>就像你看到的，对逐个移动每个数据成员非常的繁琐。注意remote_point的move赋值运算符没有做自赋值检查因为remote_integer已经做了。还需要注意，remote_point隐式声明的拷贝构造函数、赋值运算符和析构函数都正确的完成了相应功能。</p> <p>最后一个议题：你应该尽可能的为你的可拷贝的类实现move构造函数和move赋值运算符，因为编译器不会帮你生成它们。这样，不仅能在平时使用这些类时从move语义获得好处，STL容器和通用算法也可以得到move语义的好处，因为它们可以用移动代替昂贵的复制了。</p> <h2>转发的问题</h2> <p>C++98/03中关于左值、右值、引用和模板的规则看起来非常完美。直到程序员尝试去写一些高度泛化的代码时，问题出现了。假设你要写一个完全泛化的函数outer()，它的目的是获取任意数目，任意类型的参数，然后将它们转发给函数inner()。已经有了一些不错的解决方案，比如工厂方法make_shared&lt;T&gt;(args)将args转发给T的构造函数，并且返回一个shared_ptr&lt;T&gt;。（这样就把T类型的对象和它的引用计数存储在了同一个内存块中，效率上和侵入式引用计数一样好）像function&lt;Ret (Args)&gt;这样的包装类，可以将参数传递给其内部存储的函数对象，等等。在本篇文章中，我们只对outer()将参数转发给inner()感兴趣。至于outer()的返回值类型如何推定，那是另外一个问题。（有时候很简单，比如make_shared&lt;T&gt;(args)总是返回shared_ptr&lt;T&gt;。但要完全解决这个问题，就需要用到C++0x的特性decltype了）</p> <p>没有参数的情况就不讨论了，当参数为一个的情况时，让我们尝试去写一下outer()：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td>template &lt;typename T&gt; void outer(T&amp; t) {<br> &nbsp;&nbsp;&nbsp;  inner(t);<br> }</td> </tr> </tbody> </table> </div> <p>这个outer()的问题是它不能转发右值性质的参数。如果inner()接受参数const int&amp;，inner(5)没有问题，但outer(5)通不过编译，T会被推导为int，而int&amp;不能绑定5。</p> <p>好，让我们再来尝试：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td>template &lt;typename T&gt; void outer(const T&amp; t) {<br> &nbsp;&nbsp;&nbsp;  inner(t);<br> }</td> </tr> </tbody> </table> </div> <p>这样，如果inner()接受参数为int&amp;，那就违反了常量约束，因此通不过编译。</p> <p>如果你可以分别针对T&amp;和const T&amp;重载，outer()确实能够工作，然后你就能够像使用inner()一样使用outer()。</p> <p>不幸的是，当参数增多时，你需要非常繁琐的写一大堆重载函数：T1&amp;和const T1&amp;，T2&amp;和const T2&amp; ..等等。对于每个参数的增加，都会导致重载个数指数级的增加。(VC9 SP1里面的std::tr1::bind()函数非常牛×的为前5个参数做了这样的重载，包含了63个重载形式。否则的话，你就得给使用者解释为什么不能给函数对象绑定像1729这样的右值参数。为了产生出这些重载函数，需要使用令人想吐的预处理机制，恶心到你都不想去碰它)</p> <p>转发的问题在C++98/03中是比较严重的，并且本质上无法解决（除了使用令人想吐的预处理机制，那会显著的降低编译速度，并且导致代码可读性超差无比）。但是，右值引用优雅的解决了这个转发问题。</p> <p>（我已经在解释move语义模型之前解释了初始化和重载判定，但是现在我将先解说一下完美转发模型，然后再解释模板类型推导和引用退化规则。这样貌似更好一些）</p> <h2>完美转发：模型</h2> <p>完美转发可以让你只写一个函数模板就能实现接受N个任意类型的参数并且将它们透明的转发给任意的函数。它们的常量/变量/左值/右值的属性都会得到保留，让你像使用inner()一样使用outer()，还可以和move语义一起工作而获得额外的好处（C++0x的可变长模板参数解决了“任意数目的参数”的问题，我们可以把N看做是任意数目）。猛一看可能有点神奇，但其实很简单：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type perfect.cpp<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> using namespace std;</p> <p>template &lt;typename T&gt; struct Identity {<br> &nbsp;&nbsp;&nbsp;  typedef T type;<br> };</p> <p>template &lt;typename T&gt; T&amp;&amp; Forward(typename Identity&lt;T&gt;::type&amp;&amp; t) {<br> &nbsp;&nbsp;&nbsp;  return t;<br> }</p> <p>void inner(int&amp;, int&amp;) {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;inner(int&amp;, int&amp;)&quot; &lt;&lt; endl;<br> }</p> <p>void inner(int&amp;, const int&amp;) {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;inner(int&amp;, const int&amp;)&quot; &lt;&lt; endl;<br> }</p> <p>void inner(const int&amp;, int&amp;) {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;inner(const int&amp;, int&amp;)&quot; &lt;&lt; endl;<br> }</p> <p>void inner(const int&amp;, const int&amp;) {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;inner(const int&amp;, const int&amp;)&quot; &lt;&lt; endl;<br> }</p> <p><strong>template &lt;typename T1, typename T2&gt; void outer(T1&amp;&amp; t1, T2&amp;&amp; t2) {<br> &nbsp;&nbsp;&nbsp;  inner(Forward&lt;T1&gt;(t1), Forward&lt;T2&gt;(t2));<br> }</strong></p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  int a = 1;<br> &nbsp;&nbsp;&nbsp;  const int b = 2;</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Directly calling inner().&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  inner(a, a);<br> &nbsp;&nbsp;&nbsp;  inner(b, b);<br> &nbsp;&nbsp;&nbsp;  inner(3, 3);</p> <p>&nbsp;&nbsp;&nbsp;  inner(a, b);<br> &nbsp;&nbsp;&nbsp;  inner(b, a);</p> <p>&nbsp;&nbsp;&nbsp;  inner(a, 3);<br> &nbsp;&nbsp;&nbsp;  inner(3, a);</p> <p>&nbsp;&nbsp;&nbsp;  inner(b, 3);<br> &nbsp;&nbsp;&nbsp;  inner(3, b);</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl &lt;&lt; &quot;Calling outer().&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  outer(a, a);<br> &nbsp;&nbsp;&nbsp;  outer(b, b);<br> &nbsp;&nbsp;&nbsp;  outer(3, 3);</p> <p>&nbsp;&nbsp;&nbsp;  outer(a, b);<br> &nbsp;&nbsp;&nbsp;  outer(b, a);</p> <p>&nbsp;&nbsp;&nbsp;  outer(a, 3);<br> &nbsp;&nbsp;&nbsp;  outer(3, a);</p> <p>&nbsp;&nbsp;&nbsp;  outer(b, 3);<br> &nbsp;&nbsp;&nbsp;  outer(3, b);<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 perfect.cpp<br> perfect.cpp</p> <p>C:\Temp&gt;perfect<br> Directly calling inner().<br> inner(int&amp;, int&amp;)<br> inner(const int&amp;, const int&amp;)<br> inner(const int&amp;, const int&amp;)<br> inner(int&amp;, const int&amp;)<br> inner(const int&amp;, int&amp;)<br> inner(int&amp;, const int&amp;)<br> inner(const int&amp;, int&amp;)<br> inner(const int&amp;, const int&amp;)<br> inner(const int&amp;, const int&amp;)</p> <p>Calling outer().<br> inner(int&amp;, int&amp;)<br> inner(const int&amp;, const int&amp;)<br> inner(const int&amp;, const int&amp;)<br> inner(int&amp;, const int&amp;)<br> inner(const int&amp;, int&amp;)<br> inner(int&amp;, const int&amp;)<br> inner(const int&amp;, int&amp;)<br> inner(const int&amp;, const int&amp;)<br> inner(const int&amp;, const int&amp;)</p> </td> </tr> </tbody> </table> </div> <p>太帅了！实现完美转发只需要写两行！</p> <p>上面代码示范了怎样透明的将t1和t2转发给inner()；inner()可以知道它们的左值性、右值性、常量性，就像它被直接调用一样。</p> <p>就像std::move()一样，std::identity和std::forward()被定义在C++0x的&lt;utility&gt;头文件（VC10中会有）；我已经演示了它们是如何实现的。（下面我将交替视使用std::identity和我自己实现的Identity，std::forward()和Forward，因为它们实现方法是相同的）</p> <p>下面，让我们进行魔法揭秘吧。其实它依赖于模版参数推导和引用折叠技术。</p> <p>下转<a href="http://hi.baidu.com/icexile/blog/item/82b8084eeab430c0d0c86a0c.html" target="_blank">【翻译】VC10中的C++0x新特性：右值引用(rvalue references) （3）</a></p></div></p> <a href="http://hi.baidu.com/icexile/blog/item/87f7ee88339f229ea5c27239.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/icexile/blog/category/visual%20c%2B%2B">visual c++</a>&nbsp;<a href="http://hi.baidu.com/icexile/blog/item/87f7ee88339f229ea5c27239.html#comment">查看评论</a>]]></description>
        <pubDate>2009年11月11日 星期三  下午 06:13</pubDate>
        <category><![CDATA[visual c++]]></category>
        <author><![CDATA[Icexile]]></author>
		<guid>http://hi.baidu.com/icexile/blog/item/87f7ee88339f229ea5c27239.html</guid>
</item>

<item>
        <title><![CDATA[【翻译】VC10中的C++0x新特性：右值引用(rvalue references) （1）]]></title>
        <link><![CDATA[http://hi.baidu.com/icexile/blog/item/e8ad79344f43aa44241f1462.html]]></link>
        <description><![CDATA[
		
		<p><div ><p><a href="http://hi.baidu.com/icexile">零度の冰</a>翻译，<a href="http://blogs.msdn.com/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx" target="_blank">原文地址在此</a>，转载请注明<a href="http://hi.baidu.com/icexile/blog/item/e8ad79344f43aa44241f1462.html">出处</a>。</p> <p>本系列的<a href="http://hi.baidu.com/icexile/blog/item/a9836460f05fcbd58cb10dd0.html" target="_blank">第一部分</a>讲述了<strong>lambda表达式</strong>、<strong>auto关键字</strong>和<strong>static_assert</strong>。</p> <p>本文将描述<strong>右值引用</strong>，和随它而来的两个新概念：<strong>Move语义(move semantics)</strong>和<strong>完美转发(perfect forwarding)</strong>。这篇文章会很长，因为我会详细解释右值引用是如何工作的。最开始的时候你可能会觉得有点乱，因为很少有C++98/03程序员熟悉<strong>左值(lvalue)</strong>和<strong>右值(rvalue)</strong>区分的。</p> <p>但毋须退缩，因为使用右值引用很简单。在你自己的代码中，不管是实现move语义还是完美转发，都可以归结为下面我将要描述的简单模式。并且，学习右值引用是非常值得的，因为move语义可以产生数量级上的性能提升，完美转发使得编写高度通用的代码非常的容易。</p> <h2>C++98/03中的左值和右值</h2> <p>为了理解C++0x中的右值引用，必须首先理解C++98/03中的左值和右值。(译注：按照俺的理解，左值就是能够放在=左边被赋值的东东，右值就是不能放在=左边而只能放在=右边的东东……也不知道对也不对)</p> <p>术语“左值”和“右值”挺乱的，因为它们的历史就比较乱…… 这些概念最初来源与C，后在C++上弄得比较复杂。为了节约时间，我跳过去它们的历史不说，而直接阐述它们在C++98/03中是怎么工作的。</p> <p>左值是超越单个表达式而持续存在的。例如，obj，*ptr，ptr[index]，++x，它们都属于左值。</p> <p>右值是临时对象，它们只存活在单个的表达式中，并在该表达式结束后被销毁。例如1729，x + y，std::string(&quot;meow&quot;)和x++，都是右值。</p> <p>（译注：lvalue-&gt;左值，const lvalue-&gt;常量左值，rvalue-&gt;右值，const rvalue-&gt;常量右值，下文视情况使用中文或英文）</p> <p>注意 x++ 和 ++x 的区别：如果我们声明 int x = 0，则x是左值，并且语句声明了一个持久的对象。++x 也是一个左值，它修改并且返回了这个持久对象x；但是，x++却是右值，因为它把持久对象x拷贝了一份，修改了x的值，然后返回的是修改之前的拷贝，这份拷贝是临时性质的。x++ 和 ++x 都递增了x，但++x递增返回自增后的x本身，x++返回的是x自增前的一份拷贝，这份拷贝是临时性的。这就是为什么++x是左值，而x++是右值。判断左值和右值不用管这个语句干了什么，而只看该语句命名了什么（是持久性的对象还是临时对象）。</p> <p>如果你想对建立起判断左右值的直觉，另一种快速的方法就是看“取它的地址是否合法？”如果能取地址，那就是左值，否则就是右值。例如：&amp;obj，&amp;*ptr，&amp;ptr[index]和&amp;++x都是可以的，但是&amp;1729，&amp;(x + y)，&amp;std::string(&quot;meow&quot;)和&amp;x++都是不合法的。为什么可以这样判断呢？因为取地址运算符要求操作对象是左值（C++03 5.3 1/2）。为什么会有这种要求呢？因为取一个持久对象的地址是对的，但是取临时对象的地址是危险的，因为临时对象将很快被销毁。</p> <p>前面的例子忽略了运算符重载，调用重载的运算符也是一种函数调用。“函数调用是一个左值，当且仅当其返回值是一个引用。”(C++03 5.2.2/10)。因此，给定vector v(10, 1729);，v[0]是一个左值，因为operator [] ()返回一个 int&amp; （并且&amp;v[0]是有效的）。给出string s(&quot;foo&quot;);和string t(&quot;bar&quot;);，s + t是右值因为operator + ()返回string类型（并且&amp;(s + t)是非法的）。</p> <p>左值和右值都可以是变量或者常量，例如：</p> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p style="MARGIN: 0in 0in 0pt" class="MsoNormal"><span><font size="3">string one(&quot;cute&quot;);<br> const string two(&quot;fluffy&quot;);<br> string three() { return &quot;kittens&quot;; }<br> const string four() { return &quot;are an essential part of a healthy diet&quot;; }<br> one;&nbsp;&nbsp;&nbsp;&nbsp;  // modifiable lvalue<br> two;&nbsp;&nbsp;&nbsp;&nbsp;  // const lvalue<br> three(); // modifiable rvalue<br> four(); // const rvalue</font></span></p> </td> </tr> </tbody> </table> <p>Type&amp; 与lvalue绑定（并且可以被用于观察和修改它们）。它不能绑定到const lvalue上，因为这违反了常量约束。它不能绑定rvalues上，因为这样可能是极端危险的。意外地修改临时对象，只会导致临时对象和刚刚的修改操作一起消失，会导致一些难以发现的讨厌BUG，因此C++禁止这么干。（我应该提到VC有一个邪恶的扩展允许你这么干，但是如果你通过/W4选项编译，编译器会报警。）还有，它也不能绑定到const rvalue上，因为这样可能会导致双倍的错误（译注：1、非常量引用类型引用常量，2、左值引用引用右值）（细心的读者可能已经注意到了我这里没有谈到模板参数类型推导）</p> <p>const Type&amp; 可以绑定到任何东西上：lvalue, rvalue, const lvalue, const rvalue（并且可用于观察它们的变化）。</p> <p>一个引用类型是具名的，因此，一个绑定到右值的引用本身，是左值。（因为只有常量引用才能绑定到右值上，因此它会是一个const lvalue）这个有点拗口，而且会导致一些比较大的问题，因此我来进一步说明一下。给定一个函数签名void observe(const string&amp; str)，即便调用observe()时传入像上面的three()这样的右值当作参数，在此函数内部str也是一个const lvalue，其地址是可以取到的，并且在函数返回前都可用。你也可以调用observe(&quot;purr&quot;)，这将导致一个临时的string对象被构造，并且将str绑定到上面。three()、four()的返回值也是右值，但是在observe函数内部，str就是一个名字，因此它是左值。就像我上面强调的，“左值性或者是右值性是针对于表达式来说的，并不是针对于对象。”当然了，因为str可以被绑定到一个会在未来被销毁的临时对象上，所以保存其地址，在observe()返回后使用是不对的。</p> <p>你曾经将一个右值绑定到一个const Type&amp;上面并且取过它的地址吗？是的，你肯定这么干过！当你重载一个赋值运算符Foo&amp; operator=(const Foo&amp; other)，里面会有自己给自己赋值的检测 if(this != &amp;other){ copy stuff; } return *this;，这样，当你从临时对象赋值时，上述情况就发生了，例如Foo make_foo(); Foo f; f = make_foo();。</p> <p>这时候，有同学会问了，“我不能将Type&amp;与rvalue绑定，我也不能指派个啥东西与rvalue关联，那我还能修改右值吗？const rvalue和rvalue有啥不同？”这是一个非常好的问题！在C++98/03中，const rvalue和rvalue有轻微的不同：可以在rvalue的对象上调用其非常量成员函数，而const rvalue属性的对象上则不能调用。在C++0x中，答案戏剧性地变化了，导致了move语义的出现。</p> <p>祝贺你！你现在已经具有了“左值/右值感官”：看到一个表达式就能够辨认出这是左值还是右值的能力。结合const属性，你可以精确的分析给出声明void mutate(string&amp; ref)和上面的变量定义，mutate(one)是OK的，mutate(two), mutate(three()), mutate(four()), mutate(&quot;purr&quot;)都是非法的。所有的observe(one), observe(three()), observe(four())和observe(&quot;purr&quot;)都是有效的。如果你是一名C++98/03程序员，你以前是“本能的直觉”告诉你上面哪些调用是非法的，哪些是有效的。但现在，你有了“左值/右值感官”，它可以精确的告诉你为什么mutate(three())通不过编译（因为three()是一个右值，Type&amp;不能绑定到右值上）。这有用吗？对于研究语法的人，很有用，但对于普通的程序员，就没啥大用处了。毕竟，你在没有掌握太多左右值细节的情况下，得到了这项能力。但注意，相对于C++98/03，C++0x需要更加强大的左右值判断能力，你现在具有了这项牛B能力，让我们继续下去吧！</p> <h2>对象复制问题</h2> <p>C++98/03将强大的抽象能力和强大的执行效率完美结合在了一起，但它有一个问题：它过度的依赖于对象的复制了。对象都是具有值语义的，因此复制一个对象不会影响源对象，其副本也是独立的。值语义很棒， 但它有时候会导致像string, vector这样的庞大对象的不必要的复制。有些情况下返回值优化 Return Value Optimization (RVO) 和 具名返回值优化 Named Return Value Optimization (NRVO)可以减轻这个问题，但是它们也没有完全消除所有不必要的复制行为。</p> <p>最不必要的复制行为就是去复制那些即将销毁的对象。你会在复制了一夜表单后立马将原来的那份扔了吗？这太浪费了吧，你应该保留原有的那一份，而不是复制一份再扔掉原来的。这里有一个我称之为“杀手级”的例子，来源于标准委员会(N1377)。假设你有一坨string：</p> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p style="MARGIN: 0in 0in 0pt" class="MsoNormal">string s0(&quot;my mother told me that&quot;);<br> string s1(&quot;cute&quot;);<br> string s2(&quot;fluffy&quot;);<br> string s3(&quot;kittens&quot;);<br> string s4(&quot;are an essential part of a healthy diet&quot;);</p> </td> </tr> </tbody> </table> <p>然后你把他们连接起来：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td>string dest = s0 + &quot; &quot; + s1 + &quot; &quot; + s2 + &quot; &quot; + s3 + &quot; &quot; + s4;</td> </tr> </tbody> </table> </div> <p>这句话效率如何？（我们不是担心这个特例的效率问题，它也只运行几微秒而已；我们担心的是整个语言的属于上面例子这一类的效率问题）</p> <p>每次调用operator + () 都返回一个string的临时对象。上面一共调用了8次operator + ()，因此出现了8个临时的string。每次构造临时对象时，其构造函数都会动态分配一些内存然后拷贝之前连接过的所有字符。接着，其析构函数被调用，内存被释放。</p> <p>实际上，每次字符串的连接都会把之前连接过的字符串的所有字符复制一遍，因此，随着连接次数的增多，复杂度成平方级增长。啊！这真是极度的浪费啊！我们如何避免这种情况的发生呢？</p> <p>问题出在operator + ()上面，它接受两个const string&amp;或者一个const string&amp;和一个const char*作为参数，它不能判断出接受的参数到底是左值还是右值，因此它就每次创建并且返回一个临时的string。为什么知道左值或是右值很重要呢？</p> <p>当我们看s0 + &quot; &quot;时，创建一个临时对象是完全必要的。s0是左值，它命名了一个持久性的对象，因此我们不能修改它。但是当我们看(s0 + &quot; &quot;) + s1时，我们应该直接将s1的内容增加进(s0 + &quot; &quot;)创建的临时对象中，而不是创建一个新的临时对象，再把第一个临时对象扔掉。这就是<strong>move语义的关键</strong>：因为(s0 + &quot; &quot;)是个右值，一个代表临时对象的表达式，整个程序中再没有其它地方观察这个变量了。如果我们能够检测到这是个右值，我们就能任意修改它，而不影响任何其它的地方。operator + ()并不想修改它的参数，但是如果参数是可修改的右值，修改了也无妨吧？使用这种方法，每次调用operator + ()都在那个首次创建的临时string上扩展字符，这完全消掉了不必要的内存管理和复制，带给我们线性的复杂度，哦耶！</p> <p>技术层面上讲，C++0x中，每次调用operator + () 仍然返回一个独立的临时变量。但是，(s0 + &quot; &quot;) + s1中，第二个+返回的临时变量窃取了第一个+创建的临时变量的内存，并且将s1的内容接在窃取的那段内存后面（可能会导致重新申请更大的内存）。“窃取”还包括指针的修改：第二个临时变量拷贝走第一个临时变量的内存，并将其内存指针设为NULL。当第一个临时变量释放内存时，指针为空，因此它的析构函数啥也不用干。</p> <p>通常，检查可修改的右值的能力使你成为了“资源小偷”。如果被引用的右值包含任何资源（例如内存），你就可以窃取它的资源而不必拷贝它，因为它马上就会被销毁了。通过窃取右值上面的资源构造对象或者是赋值，通常称之为“move”，可move的对象具有“move语义”。</p> <p>这在很多地方都很有用，例如vector的重新分配。当一个vector需要更大的容量时，重新分配内存后，它需要将数据对象从老的内存块中移动到新的内存块，而调用它们的拷贝构造函数可能代价很昂贵（一个vector&lt;string&gt;，每个string的拷贝都需要分配内存，拷贝整个字符串）。但是等一等！在旧的内存块中的对象是马上要被销毁的，所以我们可以移动它们，而不是拷贝。在这种情况下，在旧的内存块中的元素是持久性存储的，而像old_ptr[index]这样引用这个元素的表达式是左值。如果把它们看做是右值就好了，这样就允许我们移动它们，消灭掉了拷贝构造函数的调用。（说“我想将这个左值看做右值”等价于说“我知道这是个左值，代表了一个持久性的对象，但我不在乎了，因为我即将销毁它了，或者给它重新复制了，等等。所以如果你能窃取它的资源，那就这么干吧！”）</p> <p>C++0x的右值引用给了我们检测右值和窃取右值资源的能力，这使move语义成为现实。右值引用也允许我们将左值看做是右值而实施move语义。现在，让我们看看右值语义如何工作吧。</p> <h2>右值引用：初始化</h2> <p>C++0x引入了一个新的引用类型，右值引用：Type&amp;&amp;和const Type&amp;&amp;。当前的C++0x工作草案，<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf">N2798</a> 8.3.2/2中说：“通过&amp;声明的引用叫做左值引用，通过&amp;&amp;声明的引用叫做右值引用。左值引用和右值引用是不同的类型。除非明确地指出，它们在语义上是等效的，通常被称为引用。”这意味着你需要学习它们的不同之处。</p> <p>相对于左值引用，右值引用在初始化和重载时有不同的行为。区别在于它们倾向于绑定什么类型的对象（初始化），什么类型的对象倾向于优先绑定到它们（重载）。让我们先看看初始化：</p> <ul> <li>我们已经知道了Type&amp;倾向于绑定lvalue。其它的都不行（const lvalue，rvalue，const rvalue）。</li> <li>我们已经知道了const Type&amp;倾向于绑定所有类型。</li> <li>Type&amp;&amp;倾向于绑定lvalue和rvalue，但不能绑定const lvalue和const rvalue（这违反了常量约束）。</li> <li>const Type&amp;&amp;倾向于绑定所有类型。</li> </ul> <p>这些规则看着挺神秘，但它们都是从下面两条派生出来的：</p> <ul> <li>遵守常量约束，变量引用不能绑定与常量。</li> <li>避免修改临时变量，阻止左值引用绑定到右值上。</li> </ul> <p>如果你更喜欢看编译器给出的错误信息，下面就是一例：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type initialization.cpp<br> #include &lt;string&gt;<br> using namespace std;</p> <p>string modifiable_rvalue() {<br> &nbsp;&nbsp;&nbsp;  return &quot;cute&quot;;<br> }</p> <p>const string const_rvalue() {<br> &nbsp;&nbsp;&nbsp;  return &quot;fluffy&quot;;<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  string modifiable_lvalue(&quot;kittens&quot;);<br> &nbsp;&nbsp;&nbsp;  const string const_lvalue(&quot;hungry hungry zombies&quot;);</p> <p>&nbsp;&nbsp;&nbsp;  string&amp; a = modifiable_lvalue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 16<br> &nbsp;&nbsp;&nbsp;  string&amp; b = const_lvalue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 17 - ERROR<br> &nbsp;&nbsp;&nbsp;  string&amp; c = modifiable_rvalue();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 18 - ERROR<br> &nbsp;&nbsp;&nbsp;  string&amp; d = const_rvalue();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 19 - ERROR</p> <p>&nbsp;&nbsp;&nbsp;  const string&amp; e = modifiable_lvalue;&nbsp;&nbsp;&nbsp;  // Line 21<br> &nbsp;&nbsp;&nbsp;  const string&amp; f = const_lvalue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 22<br> &nbsp;&nbsp;&nbsp;  const string&amp; g = modifiable_rvalue();  // Line 23<br> &nbsp;&nbsp;&nbsp;  const string&amp; h = const_rvalue();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 24</p> <p>&nbsp;&nbsp;&nbsp;  string&amp;&amp; i = modifiable_lvalue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 26<br> &nbsp;&nbsp;&nbsp;  string&amp;&amp; j = const_lvalue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 27 - ERROR<br> &nbsp;&nbsp;&nbsp;  string&amp;&amp; k = modifiable_rvalue();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 28<br> &nbsp;&nbsp;&nbsp;  string&amp;&amp; l = const_rvalue();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 29 - ERROR</p> <p>&nbsp;&nbsp;&nbsp;  const string&amp;&amp; m = modifiable_lvalue;&nbsp;&nbsp;  // Line 31<br> &nbsp;&nbsp;&nbsp;  const string&amp;&amp; n = const_lvalue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 32<br> &nbsp;&nbsp;&nbsp;  const string&amp;&amp; o = modifiable_rvalue(); // Line 33<br> &nbsp;&nbsp;&nbsp;  const string&amp;&amp; p = const_rvalue();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  // Line 34<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 /WX initialization.cpp<br> initialization.cpp<br> initialization.cpp(17) : error C2440: 'initializing' : cannot convert from 'const std::string' to 'std::string &amp;'<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Conversion loses qualifiers<br> initialization.cpp(18) : warning C4239: nonstandard extension used : 'initializing' : conversion from 'std::string' to 'std::string &amp;'<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  A non-const reference may only be bound to an lvalue<br> initialization.cpp(19) : error C2440: 'initializing' : cannot convert from 'const std::string' to 'std::string &amp;'<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Conversion loses qualifiers<br> initialization.cpp(27) : error C2440: 'initializing' : cannot convert from 'const std::string' to 'std::string &amp;&amp;'<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Conversion loses qualifiers<br> initialization.cpp(29) : error C2440: 'initializing' : cannot convert from 'const std::string' to 'std::string &amp;&amp;'<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Conversion loses qualifiers</p> </td> </tr> </tbody> </table> </div> <p>右值绑定到右值引用可以被用来修改临时变量。</p> <p>即使左值引用和右值引用在初始化时行为是类似的（只有18行和28行有不同），它们在重载中表现得却很不同。</p> <h2>右值引用：重载判定</h2> <p>你已经对参数为变量和常量左值引用的函数重载很熟悉了。在C++0x中，函数可以用常量或非常量右值引用重载。给出一个一元函数的所有四种重载形式，你应该发现了，每个表达式都倾向于绑定到与它对应的引用上：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type four_overloads.cpp<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;string&gt;<br> using namespace std;</p> <p>void <strong>meow(string&amp; s)</strong> {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;meow(string&amp;): &quot; &lt;&lt; s &lt;&lt; endl;<br> }</p> <p>void <strong>meow(const string&amp; s)</strong> {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;meow(const string&amp;): &quot; &lt;&lt; s &lt;&lt; endl;<br> }</p> <p>void <strong>meow(string&amp;&amp; s)</strong> {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;meow(string&amp;&amp;): &quot; &lt;&lt; s &lt;&lt; endl;<br> }</p> <p>void <strong>meow(const string&amp;&amp; s)</strong> {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;meow(const string&amp;&amp;): &quot; &lt;&lt; s &lt;&lt; endl;<br> }</p> <p>string strange() {<br> &nbsp;&nbsp;&nbsp;  return &quot;strange()&quot;;<br> }</p> <p>const string charm() {<br> &nbsp;&nbsp;&nbsp;  return &quot;charm()&quot;;<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  string up(&quot;up&quot;);<br> &nbsp;&nbsp;&nbsp;  const string down(&quot;down&quot;);</p> <p>&nbsp;&nbsp;&nbsp;  meow(up);<br> &nbsp;&nbsp;&nbsp;  meow(down);<br> &nbsp;&nbsp;&nbsp;  meow(strange());<br> &nbsp;&nbsp;&nbsp;  meow(charm());<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 four_overloads.cpp<br> four_overloads.cpp</p> <p>C:\Temp&gt;four_overloads<br> meow(string&amp;): up<br> meow(const string&amp;): down<br> meow(string&amp;&amp;): strange()<br> meow(const string&amp;&amp;): charm()</p> </td> </tr> </tbody> </table> </div> <p>在实践中，对Type&amp;，const Type&amp;，Type&amp;&amp;，const Type&amp;&amp;的重载不是非常的实用。一个更加有趣的重载是集合const Type&amp;和Type&amp;&amp;：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type two_overloads.cpp<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;string&gt;<br> using namespace std;</p> <p>void <strong>purr(const string&amp; s)</strong> {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;purr(const string&amp;): &quot; &lt;&lt; s &lt;&lt; endl;<br> }</p> <p>void <strong>purr(string&amp;&amp; s)</strong> {<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;purr(string&amp;&amp;): &quot; &lt;&lt; s &lt;&lt; endl;<br> }</p> <p>string strange() {<br> &nbsp;&nbsp;&nbsp;  return &quot;strange()&quot;;<br> }</p> <p>const string charm() {<br> &nbsp;&nbsp;&nbsp;  return &quot;charm()&quot;;<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  string up(&quot;up&quot;);<br> &nbsp;&nbsp;&nbsp;  const string down(&quot;down&quot;);</p> <p>&nbsp;&nbsp;&nbsp;  purr(up);<br> &nbsp;&nbsp;&nbsp;  purr(down);<br> &nbsp;&nbsp;&nbsp;  purr(strange());<br> &nbsp;&nbsp;&nbsp;  purr(charm());<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 two_overloads.cpp<br> two_overloads.cpp</p> <p>C:\Temp&gt;two_overloads<br> purr(const string&amp;): up<br> purr(const string&amp;): down<br> purr(string&amp;&amp;): strange()<br> purr(const string&amp;): charm()</p> </td> </tr> </tbody> </table> </div> <p>为什么会是这种结果呢？下面是绑定规则：</p> <ul> <li>上面初始化相关的规则具有否决权。</li> <li>左值非常强烈的倾向于绑定到左值引用上，右值非常强烈的倾向于绑定到右值引用上。</li> <li>变量表达式倾向于绑定到非常量引用上，但倾向性稍弱。</li> </ul> <p>（对于“否决”，我指的是决定匹配的候选函数时，被断定为不可行的函数将马上被排除在外）让我们根据规则判断一下：</p> <ul> <li>对于purr(up)，purr(const string&amp;)和purr(string&amp;&amp;)都没有被初始化规则否决掉。up是一个左值，因此它强烈地想绑定到左值引用purr(const string&amp;)上。up是可变的，所以它比较弱地倾向于绑定到可变引用purr(string&amp;&amp;)上。比较强烈的倾向purr(const string&amp;)胜出。</li> <li>对于purr(down)，初始化规则根据常量约束否定掉了purr(string&amp;&amp;)，因此purr(const string&amp;)胜出。</li> <li>对于purr(strange())，purr(const string&amp;)和purr(string&amp;&amp;)都没有被初始化规则否决掉。strange()是一个右值，因此它强烈地倾向于绑定到右值引用purr(string&amp;&amp;)上。strange()是可变的，因此它比较弱地倾向于绑定到非常量引用purr(string&amp;&amp;)上。强烈地倾向purr(string&amp;&amp;)胜出。</li> <li>对于purr(charm())，初始化规则根据常量约束否决掉了purr(string&amp;&amp;)，因此purr(const string&amp;)胜出。</li> </ul> <p>值得注意的是，当你重载const Type&amp;和Type&amp;&amp;时，变量右值绑定到了Type&amp;&amp;上，其它的都绑定到了const Type&amp;上。因此这组重载非常适合move语义。</p> <p>重要提示：函数按值返回时（而不是返回引用），它应该返回Type（就像strange()那样），而不是返回const Type（像charm()那样）。因为后者几乎没有任何作用（除了禁止非常量成员函数的调用），还妨碍了move语义的优化。</p> <h2>move语义：模型</h2> <p>这里有一个简单的class，remote_integer，它存储了一个指针，指向一个动态分配的int。它的默认构造函数、一元的构造函数、拷贝构造函数、重载赋值运算符和析构函数你都应该比较熟悉了。我又给它增加了move构造函数、move重载赋值运算符，它们被#ifdef MOVABLE条件编译，我用它来演示有这两个函数和没有他们时分别发生了什么，真正的代码不会这么干。</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type remote.cpp<br> #include &lt;stddef.h&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> using namespace std;</p> <p>class remote_integer {<br> public:<br> &nbsp;&nbsp;&nbsp;  remote_integer() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Default constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  explicit remote_integer(const int n) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Unary constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = new int(n);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer(const remote_integer&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Copy constructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (other.m_p) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = new int(*other.m_p);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } else {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;  }</p> <p>#ifdef MOVABLE<br> <strong>&nbsp;&nbsp;&nbsp;  remote_integer(remote_integer&amp;&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;MOVE CONSTRUCTOR.&quot; &lt;&lt; endl;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = other.m_p;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  other.m_p = NULL;<br> &nbsp;&nbsp;&nbsp;  }<br></strong>#endif // #ifdef MOVABLE</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer&amp; operator=(const remote_integer&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Copy assignment operator.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (this != &amp;other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (other.m_p) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = new int(*other.m_p);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } else {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return *this;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>#ifdef MOVABLE<br> <strong>&nbsp;&nbsp;&nbsp;  remote_integer&amp; operator=(remote_integer&amp;&amp; other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;MOVE ASSIGNMENT OPERATOR.&quot; &lt;&lt; endl;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (this != &amp;other) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_p = other.m_p;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  other.m_p = NULL;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return *this;<br> &nbsp;&nbsp;&nbsp;  }<br></strong>#endif // #ifdef MOVABLE</p> <p>&nbsp;&nbsp;&nbsp;  ~remote_integer() {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Destructor.&quot; &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  delete m_p;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int get() const {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return m_p ? *m_p : 0;<br> &nbsp;&nbsp;&nbsp;  }</p> <p>private:<br> &nbsp;&nbsp;&nbsp;  int * m_p;<br> };</p> <p>remote_integer square(const remote_integer&amp; r) {<br> &nbsp;&nbsp;&nbsp;  const int i = r.get();</p> <p>&nbsp;&nbsp;&nbsp;  return remote_integer(i * i);<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  remote_integer a(8);</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; a.get() &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  remote_integer b(10);</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; b.get() &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  b = square(a);</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; b.get() &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 remote.cpp<br> remote.cpp</p> <p>C:\Temp&gt;remote<br> Unary constructor.<br> 8<br> Unary constructor.<br> 10<br> Unary constructor.<br> Copy assignment operator.<br> Destructor.<br> 64<br> Destructor.<br> Destructor.</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 /<strong>DMOVABLE</strong> remote.cpp<br> remote.cpp</p> <p>C:\Temp&gt;remote<br> Unary constructor.<br> 8<br> Unary constructor.<br> 10<br> Unary constructor.<br> <strong>MOVE ASSIGNMENT OPERATOR.</strong><br> Destructor.<br> 64<br> Destructor.<br> Destructor.</p> </td> </tr> </tbody> </table> </div> <p>这里面有几点需要注意：</p> <ul> <li>拷贝和move构造函数是重载的，拷贝和move赋值运算符也是重载的。我们已经看到了const Type&amp;和Type&amp;&amp;函数重载时发生的情况。这就是为什么当move赋值运算符可用时，b = square(a)自动的选择了它。</li> <li>move拷贝构造函数和move赋值运算符简单的从别的地方窃取内存，而不是动态的申请内存。当窃取别人的内存时，我们直接拷贝了他的内存指针，并且将其置NULL。当那个对象释放时，其析构函数不会重复释放内存。</li> <li>move拷贝构造函数和move赋值运算符都需要做自赋值检测。因为像int这样的类型可以无害地做x = x，所以用户自定义类型也应该支持自赋值。自赋值通常不会发生在手写的程序代码中，但经常发生在一些算法中，例如std::sort()。在C++0x中，像std::sort()这样的算法可以移动对象，而不是拷贝它们。这时候，潜在的自赋值就存在了。</li> </ul> <p>这时，你会问move语义是否影响到了自动生成的（“隐式声明的”）构造函数和赋值运算符？</p> <ul> <li>编译器<strong>从来不</strong>自动生成move构造函数和move赋值运算符。</li> <li>包括拷贝构造函数<strong>和</strong>move构造函数，用户自定义的任何构造函数都会阻止编译器生成默认的构造函数。</li> <li>用户自定义的拷贝构造函数会阻止生成隐式的拷贝构造函数，但自定义的move拷贝构造函数<strong>不会</strong>阻止生成隐式的拷贝构造函数。</li> <li>同样，用户自定义的move赋值运算符<strong>不会</strong>阻止生成隐式的赋值运算符。</li> </ul> <p>基本上，自动生成规则不会被move语义影响，除了move构造函数的声明，声明任何构造函数都会阻止编译器生成默认构造函数。</p> <p>未完，下转<a href="http://hi.baidu.com/icexile/blog/item/87f7ee88339f229ea5c27239.html" target="_blank">【翻译】VC10中的C++0x新特性：右值引用(rvalue references) （2）</a></p></div></p> <a href="http://hi.baidu.com/icexile/blog/item/e8ad79344f43aa44241f1462.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/icexile/blog/category/visual%20c%2B%2B">visual c++</a>&nbsp;<a href="http://hi.baidu.com/icexile/blog/item/e8ad79344f43aa44241f1462.html#comment">查看评论</a>]]></description>
        <pubDate>2009年11月07日 星期六  下午 09:58</pubDate>
        <category><![CDATA[visual c++]]></category>
        <author><![CDATA[Icexile]]></author>
		<guid>http://hi.baidu.com/icexile/blog/item/e8ad79344f43aa44241f1462.html</guid>
</item>

<item>
        <title><![CDATA[【翻译】VC10中的C++0x新特性：Lambda表达式、auto关键字和static_assert]]></title>
        <link><![CDATA[http://hi.baidu.com/icexile/blog/item/a9836460f05fcbd58cb10dd0.html]]></link>
        <description><![CDATA[
		
		<p><div ><p><a href="http://hi.baidu.com/icexile">零度の冰</a>翻译，<a href="http://blogs.msdn.com/vcblog/archive/2008/10/28/lambdas-auto-and-static-assert-c-0x-features-in-vc10-part-1.aspx" target="_blank">点击进入原文</a>，转载请注明<a href="http://hi.baidu.com/icexile/blog/item/a9836460f05fcbd58cb10dd0.html">出处</a>。</p> <p>Visual Studio 2010(下称VS2010)中的Visual C++编译器包含了对4项（正式发布后可能更多）C++0x 特性的支持，分别为<strong>lambda表达式</strong>、<strong>auto关键字</strong>、<strong>static_assert</strong>，和<strong>右值引用（rvalue references）</strong>。此篇文章将对前三项进行详细解释，rvalue references将在后续文章中解释。</p> <p>相关资料：<br> C++0x language feature status:<br> <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2705.html">http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2705.html</a><br> C++0x library feature status:<br> <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2706.html">http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2706.html</a><br> C++0x Working Draft:<br> <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2798.pdf">http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2798.pdf</a></p> <h2>Lambda表达式</h2> <p>在C++0x中“lambda表达式”隐式的定义并构造了一个匿名的函数对象，它和普通的函数对象的行为是类似的。下面是“Hello World”的lambda：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type meow.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;<br> &nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), <strong>[](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; }</strong>);<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 meow.cpp &gt; NUL &amp;&amp; meow<br> 0 1 2 3 4 5 6 7 8 9</p> </td> </tr> </tbody> </table> </div> <p>代码中的“[]”叫做“lambda前导符”，它告诉编译器一个lambda表达式开始了。而“(int n)”是lambda表达式中的参数声明部分，它告诉编译器，这个匿名的函数对象中，函数调用运算符（“()”运算符）调用时接受的参数。最后“{ cout &lt;&lt; n &lt;&lt; &quot; &quot;; }”大括号语句作为这个匿名函数对象的函数调用符的函数体。默认情况下，匿名函数对象的返回值为void。</p> <p>因此，上面的C++0x代码实质上等价于下面的C++98代码：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type meow98.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;<br> <br> <strong>struct LambdaFunctor {<br> &nbsp;&nbsp;&nbsp;  void operator()(int n) const {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; n &lt;&lt; &quot; &quot;;<br> &nbsp;&nbsp;&nbsp;  }<br> };<br></strong><br> int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;<br> <br> &nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }<br> <br> &nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), <strong>LambdaFunctor()</strong>);<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }<br> <br> C:\Temp&gt;cl /EHsc /nologo /W4 meow98.cpp &gt; NUL &amp;&amp; meow98<br> 0 1 2 3 4 5 6 7 8 9</p> </td> </tr> </tbody> </table> </div> <p>现在，我不再说“那个匿名的函数对象的函数调用运算符的返回值是void”，而是直接说“这个lambda返回void”，但是，非常重要的一点是：一定要记住lambda表达式干了什么：定义了一个类（LambdaFunctor），然后构造了它的对象。</p> <p>当然了，lambda的大括号表达式中，可以包含多个语句：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type multimeow.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), <strong>[](int n) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; n;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (n % 2 == 0) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot; even &quot;;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } else {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot; odd &quot;;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;  }</strong>);</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 multimeow.cpp &gt; NUL &amp;&amp; multimeow<br> 0 even 1 odd 2 even 3 odd 4 even 5 odd 6 even 7 odd 8 even 9 odd</p> </td> </tr> </tbody> </table> </div> <p>现在，lambda也不必总是返回void，如果一个lambda的大括号表达式为{ return expression; }，那么这个lambda的返回值类型将被自动推断为expression的类型：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type cubicmeow.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;deque&gt;<br> #include &lt;iostream&gt;<br> #include &lt;iterator&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  deque d;</p> <p>&nbsp;&nbsp;&nbsp;  transform(v.begin(), v.end(), front_inserter(d), <strong>[](int n) { return n * n * n; }</strong>);</p> <p>&nbsp;&nbsp;&nbsp;  for_each(d.begin(), d.end(), [](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;</p> <p>}</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 cubicmeow.cpp &gt; NUL &amp;&amp; cubicmeow<br> 729 512 343 216 125 64 27 8 1 0</p> </td> </tr> </tbody> </table> </div> <p>这里，n * n * n的类型为int，所以，lambda返回值类型为int。</p> <p>有些更加复杂的lambda表达式无法做出类型推断，你需要显式的指定它：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type returnmeow.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;deque&gt;<br> #include &lt;iostream&gt;<br> #include &lt;iterator&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  deque d;</p> <p>&nbsp;&nbsp;&nbsp;  transform(v.begin(), v.end(), front_inserter(d), <strong>[](int n) -&gt; double {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (n % 2 == 0) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return n * n * n;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } else {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return n / 2.0;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;  }</strong>);</p> <p>&nbsp;&nbsp;&nbsp;  for_each(d.begin(), d.end(), [](double x) { cout &lt;&lt; x &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 returnmeow.cpp &gt; NUL &amp;&amp; returnmeow<br> 4.5 512 3.5 216 2.5 64 1.5 8 0.5 0</p> </td> </tr> </tbody> </table> </div> <p>“-&gt; double”是可选的“lambda返回值类型从句”。为什么返回值类型声明没有像以前声明函数的时候放在前面呢？因为如果不把“[]”放在最前面的话，编译器将无法知道这是一个lambda表达式。</p> <p>这里，如果你忘记了声明返回值类型，编译器将会报告错误：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td>C:\Temp&gt;cl /EHsc /nologo /W4 borkedreturnmeow.cpp<br> borkedreturnmeow.cpp<br> borkedreturnmeow.cpp(20) : <strong>error C3499: a lambda that has been specified to have a void return type cannot return a value<br></strong>borkedreturnmeow.cpp(22) : <strong>error C3499: a lambda that has been specified to have a void return type cannot return a value</strong></td> </tr> </tbody> </table> </div> <p>上面列出的所有lambda都是无状态的：它们构造出来的匿名函数对象不包含任何数据成员。你也可以获得有状态的lambda，方法是通过“捕获”局部变量。空白的lambda前导符“[]”表示这是一个无状态的lambda，但是在“[]”内部，你可以指定一个捕获组：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type capturekittybyvalue.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int x = 0;<br> &nbsp;&nbsp;&nbsp;  int y = 0;</p> <p>&nbsp;&nbsp;&nbsp;  // op&gt;&gt;()不会读取输入流中最后一个回车换行符，<br> &nbsp;&nbsp;&nbsp;  // 这有时候会带来很多问题。我推荐<br> &nbsp;&nbsp;&nbsp;  // 避免使用它，而使用非成员函数<br> &nbsp;&nbsp;&nbsp;  // getline(cin, str)读取一整行，<br> &nbsp;&nbsp;&nbsp;  // 然后再解析它。但是为了简洁起见，<br> &nbsp;&nbsp;&nbsp;  // 我会继续使用 op&gt;&gt;()：</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Input: &quot;;<br> &nbsp;&nbsp;&nbsp;  cin &gt;&gt; x &gt;&gt; y;</p> <p>&nbsp;&nbsp;&nbsp;  v.erase(remove_if(v.begin(), v.end(), <strong>[x, y](int n) { return x &lt; n &amp;&amp; n &lt; y; }</strong>), v.end());</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), [](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 capturekittybyvalue.cpp &gt; NUL &amp;&amp; capturekittybyvalue<br> Input: 4 7<br> 0 1 2 3 4 7 8 9</p> </td> </tr> </tbody> </table> </div> <p>如果你忘记了写捕获组，编译器会报告错误：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td>C:\Temp&gt;cl /EHsc /nologo /W4 borkedcapturekittybyvalue.cpp<br> borkedcapturekittybyvalue.cpp<br> borkedcapturekittybyvalue.cpp(27) : <strong>error C3493: 'x' cannot be implicitly captured as no default capture mode has been specified<br></strong>borkedcapturekittybyvalue.cpp(27) : <strong>error C3493: 'y' cannot be implicitly captured as no default capture mode has been specified</strong></td> </tr> </tbody> </table> </div> <p>（一会儿我将会介绍默认捕获）</p> <p>记住，lambda表达式隐式的定义了一个匿名的函数对象，“{ return x &lt; n &amp;&amp; n &lt; y; }”就是它函数调用符的函数体，所以尽管看起来大括号语句是在main()的范围内，但在概念上它是在main()函数范围之外的，lambda表达式中不能使用没有捕获的main()函数内的局部变量。</p> <p>这是把上面程序等价转换后的代码：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type capturekittybyvalue98.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;iterator&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p><strong>class LambdaFunctor {<br> public:<br> &nbsp;&nbsp;&nbsp;  LambdaFunctor(int a, int b) : m_a(a), m_b(b) { }</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;  bool operator()(int n) const { return m_a &lt; n &amp;&amp; n &lt; m_b; }</strong></p> <p><strong>private:<br> &nbsp;&nbsp;&nbsp;  int m_a;<br> &nbsp;&nbsp;&nbsp;  int m_b;<br> };</strong></p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int x = 0;<br> &nbsp;&nbsp;&nbsp;  int y = 0;</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Input: &quot;;<br> &nbsp;&nbsp;&nbsp;  cin &gt;&gt; x &gt;&gt; y; // EVIL!</p> <p>&nbsp;&nbsp;&nbsp;  v.erase(remove_if(v.begin(), v.end(), <strong>LambdaFunctor(x, y)</strong>), v.end());</p> <p>&nbsp;&nbsp;&nbsp;  copy(v.begin(), v.end(), ostream_iterator(cout, &quot; &quot;));<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 capturekittybyvalue98.cpp &gt; NUL &amp;&amp; capturekittybyvalue98<br> Input: 4 7<br> 0 1 2 3 4 7 8 9</p> </td> </tr> </tbody> </table> </div> <p>这里，你可以清楚的看到捕获变量是按值传递的。局部变量的拷贝被存储在了函数对象中。这样，函数对象存活的时间可以比被捕获的局部变量长。但是，需要注意几点：(a)捕获的变量在lambda中不可修改，因为默认情况下生成的是const函数调用运算符；(b)有些对象的复制操作开销比较大；(c)局部变量的更新将不会影响lambda内已经被捕获过的副本（这符合通常的值传递语义）。一会儿，我将解释在需要的时候如何应对上述三种情况。</p> <p>但是首先，如果你想捕获所有的局部变量，可以不必逐项列出它们，而只需告诉编译器“按值传递捕获所有变量”。实现方式是使用前导符“[=]”：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type defaultcapturekittybyvalue.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int x = 0;<br> &nbsp;&nbsp;&nbsp;  int y = 0;</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;Input: &quot;;<br> &nbsp;&nbsp;&nbsp;  cin &gt;&gt; x &gt;&gt; y; // EVIL!</p> <p>&nbsp;&nbsp;&nbsp;  v.erase(remove_if(v.begin(), v.end(), <strong>[=](int n) { return x &lt; n &amp;&amp; n &lt; y; }</strong>), v.end());</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), [](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 defaultcapturekittybyvalue.cpp &gt; NUL &amp;&amp; defaultcapturekittybyvalue<br> Input: 4 7<br> 0 1 2 3 4 7 8 9</p> </td> </tr> </tbody> </table> </div> <p>当编译器看到lambda中的x和y，会将它们从main()中按值捕获进来。</p> <p>对于情况(a)无法修改捕获的变量，如何处理呢？默认情况下，lambda的函数调用运算符是const的，但是你可以通过mutable关键字将其变为非const：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type capturekittybymutablevalue.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int x = 1;<br> &nbsp;&nbsp;&nbsp;  int y = 1;</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), <strong>[=](int&amp; r) mutable {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  const int old = r;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  r *= x * y;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  x = y;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  y = old;<br> &nbsp;&nbsp;&nbsp;  }</strong>);</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), [](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; x &lt;&lt; &quot;, &quot; &lt;&lt; y &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 capturekittybymutablevalue.cpp &gt; NUL &amp;&amp; capturekittybymutablevalue<br> 0 0 0 6 24 60 120 210 336 504<br> 1, 1</p> </td> </tr> </tbody> </table> </div> <p>上面代码将v中每个变量变为自身和它前两个变量相乘的结果。注意，(d)对捕获过的变量操作不会影响到原来变量本身（又是通常的值传递语义）。</p> <p>如果你想对付(b)，(c)，(d)的话：使用引用传递。方法是在前导符中这样写捕获组：“[&amp;x, &amp;y]”：</p> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type capturekittybyreference.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int x = 1;<br> &nbsp;&nbsp;&nbsp;  int y = 1;</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), <strong>[&amp;x, &amp;y](int&amp; r) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  const int old = r;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  r *= x * y;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  x = y;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  y = old;<br> &nbsp;&nbsp;&nbsp;  }</strong>);</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), [](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; x &lt;&lt; &quot;, &quot; &lt;&lt; y &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 capturekittybyreference.cpp &gt; NUL &amp;&amp; capturekittybyreference<br> 0 0 0 6 24 60 120 210 336 504<br> 8, 9</p> </td> </tr> </tbody> </table> <p>注意capturekittybyreference.cpp中的变化：(1)lambda前导符“[&amp;x, &amp;y]”，(2)mutable消失了，(3)局部变量x, y的值最终变为了8、9，lambda中对它们的修改反映到了表达式外部。</p> <p>下面是翻译后的等价代码：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type capturekittybyreference98.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;iterator&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p><strong>#pragma warning(push)<br> #pragma warning(disable: 4512) // assignment operator could not be generated</strong></p> <p><strong>class LambdaFunctor {<br> public:<br> &nbsp;&nbsp;&nbsp;  LambdaFunctor(int&amp; a, int&amp; b) : m_a(a), m_b(b) { }</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;  void operator()(int&amp; r) const {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  const int old = r;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  r *= m_a * m_b;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_a = m_b;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m_b = old;<br> &nbsp;&nbsp;&nbsp;  }</strong></p> <p><strong>private:<br> &nbsp;&nbsp;&nbsp;  int&amp; m_a;<br> &nbsp;&nbsp;&nbsp;  int&amp; m_b;<br> };</strong></p> <p><strong>#pragma warning(pop)</strong></p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int x = 1;<br> &nbsp;&nbsp;&nbsp;  int y = 1;</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), <strong>LambdaFunctor(x, y)</strong>);</p> <p>&nbsp;&nbsp;&nbsp;  copy(v.begin(), v.end(), ostream_iterator(cout, &quot; &quot;));<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; x &lt;&lt; &quot;, &quot; &lt;&lt; y &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 capturekittybyreference98.cpp &gt; NUL &amp;&amp; capturekittybyreference98<br> 0 0 0 6 24 60 120 210 336 504<br> 8, 9</p> </td> </tr> </tbody> </table> </div> <p>（当使用lambda的时候，编译会为lambda的定义部分自动关闭C4512号警告）</p> <p>当你按照引用传递捕获局部变量时，生成的函数对象存储的是局部变量的引用，这样避免了复制，并且允许函数对象观察这些局部变量的变化甚至修改它们的值。（注意当前生成的函数调用运算符仍然是const修饰的，表示函数对象的成员变量不可更改，而引用类型本身就是不能更改的，但我们可以更改它引用的变量。函数调用运算符的常量性仍然得到保持）</p> <p>当然了，如果一个lambda的函数对象的寿命长于它所引用的局部变量，程序会down掉。</p> <p>再一次的，你可以使用默认捕获：“[&amp;]”代表“按引用传递捕获所有”。</p> <p>如何混合值传递捕获和引用传递捕获呢？你可以用“[a, b, c, &amp;d, e, &amp;f, g]”。也可以指定一个默认捕获方式，但对于特殊的变量指定不同的捕获方式：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type overridekitty.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  int sum = 0;<br> &nbsp;&nbsp;&nbsp;  int product = 1;</p> <p>&nbsp;&nbsp;&nbsp;  int x = 1;<br> &nbsp;&nbsp;&nbsp;  int y = 1;</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), <strong>[=, &amp;sum, &amp;product](int&amp; r) mutable {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  sum += r;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (r != 0) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  product *= r;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  const int old = r;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  r *= x * y;</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  x = y;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  y = old;<br> &nbsp;&nbsp;&nbsp;  }</strong>);</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), [](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;sum: &quot; &lt;&lt; sum &lt;&lt; &quot;, product: &quot; &lt;&lt; product &lt;&lt; endl;<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;x: &quot; &lt;&lt; x &lt;&lt; &quot;, y: &quot; &lt;&lt; y &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 overridekitty.cpp &amp;&amp; overridekitty<br> overridekitty.cpp<br> 0 0 0 6 24 60 120 210 336 504<br> sum: 45, product: 362880<br> x: 1, y: 1</p> </td> </tr> </tbody> </table> </div> <p>这里我们想按值捕获x, y（因为我们不想让内部对x, y副本的修改影响到他们本身），按引用捕获sum和product（因为我们确实想在lambda内部修改它们本身的值）。使用“[&amp;, x, y]”前导符会导致同样的结果。</p> <p>接下来，如果你想做下面的事情该怎么办？</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type memberkitty.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>class Kitty {<br> public:<br> &nbsp;&nbsp;&nbsp;  explicit Kitty(int toys) : m_toys(toys) { }</p> <p>&nbsp;&nbsp;&nbsp;  void meow(const vector&amp; v) const {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), <strong>[m_toys](int n) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;If you gave me &quot; &lt;&lt; n &lt;&lt; &quot; toys, I would have &quot; &lt;&lt; n + m_toys &lt;&lt; &quot; toys total.&quot; &lt;&lt; endl;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</strong>);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>private:<br> &nbsp;&nbsp;&nbsp;  int m_toys;<br> };</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 3; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  Kitty k(5);<br> &nbsp;&nbsp;&nbsp;  k.meow(v);<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 memberkitty.cpp<br> memberkitty.cpp<br> memberkitty.cpp(12) : <strong>error C3480: 'Kitty::m_toys': a lambda capture variable must be from an enclosing function scope</strong></p> </td> </tr> </tbody> </table> </div> <p>lambda表达式允许捕获局部变量，但是数据成员不是局部变量。用一种特殊的方法，你可以捕获“this”：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type workingmemberkitty.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>class Kitty {<br> public:<br> &nbsp;&nbsp;&nbsp;  explicit Kitty(int toys) : m_toys(toys) { }</p> <p>&nbsp;&nbsp;&nbsp;  void meow(const vector&amp; v) const {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), <strong>[this](int n) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;If you gave me &quot; &lt;&lt; n &lt;&lt; &quot; toys, I would have &quot; &lt;&lt; n + m_toys &lt;&lt; &quot; toys total.&quot; &lt;&lt; endl;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</strong>);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>private:<br> &nbsp;&nbsp;&nbsp;  int m_toys;<br> };</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 3; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  Kitty k(5);<br> &nbsp;&nbsp;&nbsp;  k.meow(v);<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 workingmemberkitty.cpp &gt; NUL &amp;&amp; workingmemberkitty<br> If you gave me 0 toys, I would have 5 toys total.<br> If you gave me 1 toys, I would have 6 toys total.<br> If you gave me 2 toys, I would have 7 toys total.</p> </td> </tr> </tbody> </table> </div> <p>当你捕获了this以后，m_toys就可以使用了，它隐式的表示this-&gt;m_toys，你也可以显示的说明this-&gt;m_toys。（在lambda表达式中，只有捕获了this后才可以使用它，你永远无法得到lambda表达式本身的this指针）</p> <p>你也可以隐式的捕获this：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type implicitmemberkitty.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>class Kitty {<br> public:<br> &nbsp;&nbsp;&nbsp;  explicit Kitty(int toys) : m_toys(toys) { }</p> <p>&nbsp;&nbsp;&nbsp;  void meow(const vector&amp; v) const {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), <strong>[=](int n) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;If you gave me &quot; &lt;&lt; n &lt;&lt; &quot; toys, I would have &quot; &lt;&lt; n + m_toys &lt;&lt; &quot; toys total.&quot; &lt;&lt; endl;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</strong>);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>private:<br> &nbsp;&nbsp;&nbsp;  int m_toys;<br> };</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 3; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  Kitty k(5);<br> &nbsp;&nbsp;&nbsp;  k.meow(v);<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 implicitmemberkitty.cpp &gt; NUL &amp;&amp; implicitmemberkitty<br> If you gave me 0 toys, I would have 5 toys total.<br> If you gave me 1 toys, I would have 6 toys total.<br> If you gave me 2 toys, I would have 7 toys total.</p> </td> </tr> </tbody> </table> </div> <p>你也可以使用“[&amp;]”,但是它不会影响this的捕获方式（永远按值传递）。“[&amp;this]”是不允许的。</p> <p>如果你想得到一个空参数的lambda，可以直接省略小括号部分：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type nullarykitty.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;iterator&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  int i = 0;</p> <p>&nbsp;&nbsp;&nbsp;  generate_n(back_inserter(v), 10, <strong>[&amp;] { return i++; }</strong>);</p> <p>&nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), [](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;</p> <p>&nbsp;&nbsp;&nbsp;  cout &lt;&lt; &quot;i: &quot; &lt;&lt; i &lt;&lt; endl;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 nullarykitty.cpp &gt; NUL &amp;&amp; nullarykitty<br> 0 1 2 3 4 5 6 7 8 9<br> i: 10</p> </td> </tr> </tbody> </table> </div> <p>这比“[&amp;]() { return i++; }”少两个字符。到底这么干好不好就得看自己怎么想了。</p> <p>搞笑的是，这意味这下面代码在C++0x中是有效的：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td>C:\Temp&gt;type nokitty.cpp<br> int main() {<br> &nbsp;&nbsp;&nbsp;  <strong>[](){}</strong>();<br> &nbsp;&nbsp;&nbsp;  <strong>[]{}</strong>();<br> }</td> </tr> </tbody> </table> </div> <p>上面构造了俩啥也不干的lambda（一个有参数声明，一个没有），然后马上调用它们（最后的那个空的小括号）。</p> <p>注意语法上可选的lambda参数声明包括：</p> <p>(参数声明)<sub>[可选]</sub>mutable<sub>[可选]</sub>可能抛的异常<sub>[可选]</sub>lambda返回值类型<sub>[可选]</sub></p> <p>因此，如果要指定mutable或是 -&gt; return type，那么空的()就不能省略。</p> <p>最后，由于lambda生成的是普通的函数对象，你可以将其存储在 std::tr1::function 里面：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type tr1kitty.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;functional&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;<br> using namespace std::tr1;</p> <p>void meow(const vector&amp; v, const function&amp; f) {<br> &nbsp;&nbsp;&nbsp;  for_each(v.begin(), v.end(), f);<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector v;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 10; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  v.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  meow(v, <strong>[](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; }</strong>);<br> &nbsp;&nbsp;&nbsp;  meow(v, <strong>[](int n) { cout &lt;&lt; n * n &lt;&lt; &quot; &quot;; }</strong>);</p> <p>&nbsp;&nbsp;&nbsp;  <strong>function g = [](int n) { cout &lt;&lt; n * n * n &lt;&lt; &quot; &quot;; };</strong></p> <p>&nbsp;&nbsp;&nbsp;  meow(v, g);</p> <p>}</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 tr1kitty.cpp &gt; NUL &amp;&amp; tr1kitty<br> 0 1 2 3 4 5 6 7 8 9<br> 0 1 4 9 16 25 36 49 64 81<br> 0 1 8 27 64 125 216 343 512 729</p> </td> </tr> </tbody> </table> </div> <h2>auto</h2> <p>auto关键字在C++98里面就有，但是它实际上没有干什么事。在C++0x中，它被重新定义为类型自动推断。当使用它声明变量的时候，意思是说“把该变量的类型设置为初始化它的那个变量的类型”。</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type autocat.cpp<br> #include &lt;iostream&gt;<br> #include &lt;map&gt;<br> #include &lt;ostream&gt;<br> #include &lt;regex&gt;<br> #include &lt;string&gt;<br> <map>using namespace std;<br> using namespace std::tr1; <p>int main() {<br> &nbsp;&nbsp;&nbsp;  map m;</p> <p>&nbsp;&nbsp;&nbsp;  const regex r(&quot;(\\w+) (\\w+)&quot;);</p> <p>&nbsp;&nbsp;&nbsp;  for (string s; getline(cin, s); ) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  smatch results;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (regex_match(s, results, r)) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  m[results[1]] = results[2];<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  for (<strong>auto</strong> i = m.begin(); i != m.end(); ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  cout &lt;&lt; i-&gt;second &lt;&lt; &quot; are &quot; &lt;&lt; i-&gt;first &lt;&lt; endl;<br> &nbsp;&nbsp;&nbsp;  }<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 autocat.cpp &gt; NUL &amp;&amp; autocat<br> cute kittens<br> ugly puppies<br> evil goblins<br> ^Z<br> kittens are cute<br> goblins are evil<br> puppies are ugly</p> <p>map::iterator, your decade-long reign of terror has come to an end!</p> </map></p> </td> </tr> </tbody> </table> </div> <p>（注意m.begin()返回的是iterator，不是const_iterator，因为map本身不const，C++0x中cbegin()允许从非const容器中请求一个const_iterator。）</p> <h2>lambda和auto</h2> <p>之前提到过将lambda存储在std::tr1::function中。但是尽量不要这么做，因为std::tr1::function块头比较大开销也很大。如果你想复用一个lambda，或者只是想简单的给它命名，你可以使用auto。下面有一个非常简洁的例子：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type autolambdakitty.cpp<br> #include &lt;algorithm&gt;<br> #include &lt;iostream&gt;<br> #include &lt;ostream&gt;<br> #include &lt;vector&gt;<br> using namespace std;</p> <p>template void keep_if(vector&amp; v, Predicate pred) {<br> &nbsp;&nbsp;&nbsp;  <strong>auto notpred = [&amp;](const T&amp; t) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return !pred(t);<br> &nbsp;&nbsp;&nbsp;  };</strong></p> <p>&nbsp;&nbsp;&nbsp;  v.erase(remove_if(v.begin(), v.end(), <strong>notpred</strong>), v.end());<br> }</p> <p>template void print(const Container&amp; c) {<br> &nbsp;&nbsp;&nbsp;  for_each(c.begin(), c.end(), [](const typename Container::value_type&amp; e) { cout &lt;&lt; e &lt;&lt; &quot; &quot;; });<br> &nbsp;&nbsp;&nbsp;  cout &lt;&lt; endl;<br> }</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  vector a;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 0; i &lt; 100; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  a.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  vector b;</p> <p>&nbsp;&nbsp;&nbsp;  for (int i = 100; i &lt; 200; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  b.push_back(i);<br> &nbsp;&nbsp;&nbsp;  }</p> <p>&nbsp;&nbsp;&nbsp;  <strong>auto prime = [](const int n) -&gt; bool {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (n &lt; 2) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return false;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  for (int i = 2; i &lt;= n / i; ++i) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  if (n % i == 0) {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return false;<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  }</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return true;<br> &nbsp;&nbsp;&nbsp;  };</strong></p> <p>&nbsp;&nbsp;&nbsp;  keep_if(a, <strong>prime</strong>);<br> &nbsp;&nbsp;&nbsp;  keep_if(b, <strong>prime</strong>);</p> <p>&nbsp;&nbsp;&nbsp;  print(a);<br> &nbsp;&nbsp;&nbsp;  print(b);<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 autolambdakitty.cpp<br> autolambdakitty.cpp</p> <p>C:\Temp&gt;autolambdakitty<br> 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97<br> 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199</p> </td> </tr> </tbody> </table> </div> <p>notpred是一个否定性质的lambda！注意，我们不能使用C++98里面的not1()，它要求你写的“断定”部分从unary_function中派生，但是lambda不是。</p> <h2>static_assert</h2> <p>static_assert允许你使用自定义的错误消息引发编译错误：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="90%"> <tbody> <tr valign="top"> <td> <p>C:\Temp&gt;type staticfluffykitten.cpp<br> template struct Kitten {<br> &nbsp;&nbsp;&nbsp;  <strong>static_assert(N &lt; 2, &quot;Kitten requires N &lt; 2.&quot;);</strong><br> };</p> <p>int main() {<br> &nbsp;&nbsp;&nbsp;  Kitten&lt;1&gt; peppermint;</p> <p>&nbsp;&nbsp;&nbsp;  Kitten&lt;3&gt; jazz;<br> }</p> <p>C:\Temp&gt;cl /EHsc /nologo /W4 staticfluffykitten.cpp<br> staticfluffykitten.cpp<br> staticfluffykitten.cpp(2) : <strong>error C2338: Kitten requires N &lt; 2.</strong><br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  staticfluffykitten.cpp(8) : see reference to class template instantiation 'Kitten' being compiled<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  with<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  [<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  N=3<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  ]<br></p> </td> </tr> </tbody> </table> </div> <p>Stephan T. Lavavej<br> Visual C++ Libraries Developer</p> <p>译著：本人纯属一时兴起将此文翻译，错误多多，有问题的同志请留言。</p></div></p> <a href="http://hi.baidu.com/icexile/blog/item/a9836460f05fcbd58cb10dd0.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/icexile/blog/category/visual%20c%2B%2B">visual c++</a>&nbsp;<a href="http://hi.baidu.com/icexile/blog/item/a9836460f05fcbd58cb10dd0.html#comment">查看评论</a>]]></description>
        <pubDate>2009年11月06日 星期五  下午 02:37</pubDate>
        <category><![CDATA[visual c++]]></category>
        <author><![CDATA[Icexile]]></author>
		<guid>http://hi.baidu.com/icexile/blog/item/a9836460f05fcbd58cb10dd0.html</guid>
</item>

<item>
        <title><![CDATA[解决Xmarks不能同步的问题]]></title>
        <link><![CDATA[http://hi.baidu.com/icexile/blog/item/ad2b91012a241b0c1d95838d.html]]></link>
        <description><![CDATA[
		
		<div>
<p>GFW无比强大，竟然墙掉了firefox书签同步插件xmarks……</p>
<p>目前还有效的解决方法是，把下面的文本加入 %systemroot%\System32\drivers\etc\hosts 文件中。</p>
<p>64.147.188.86 www.xmarks.com<br>
64.147.188.92 api.xmarks.com<br>
64.147.188.89 login.xmarks.com<br>
64.147.188.87 sync.xmarks.com<br>
64.147.188.86 static.xmarks.com<br>
64.147.188.86 download.xmarks.com<br>
64.147.188.86 my.xmarks.com</p>
<p>然后将xmarks同步选项设置为全部加密。</p>
<p>以后如果这样也不行了，那就只有用tor了，只不过目前连接tor也需要中继服务器才能成功，国家局域网即将建成！</p>
</div> <a href="http://hi.baidu.com/icexile/blog/item/ad2b91012a241b0c1d95838d.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/icexile/blog/category/%B2%D9%D7%F7%CF%B5%CD%B3">操作系统</a>&nbsp;<a href="http://hi.baidu.com/icexile/blog/item/ad2b91012a241b0c1d95838d.html#comment">查看评论</a>]]></description>
        <pubDate>2009年10月25日 星期日  下午 08:27</pubDate>
        <category><![CDATA[操作系统]]></category>
        <author><![CDATA[Icexile]]></author>
		<guid>http://hi.baidu.com/icexile/blog/item/ad2b91012a241b0c1d95838d.html</guid>
</item>

<item>
        <title><![CDATA[函数_tprintf、_tprintf_s与ATL中Unicode转换类CA2CT之间的奇怪问题]]></title>
        <link><![CDATA[http://hi.baidu.com/icexile/blog/item/d67cfbfd97818c4fd7887d5a.html]]></link>
        <description><![CDATA[
		
		<p><div ><p>看下面一段代码：</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="%80"> <tbody> <tr valign="top"> <td> <p>#include &lt;atlbase.h&gt;<br> #include &lt;atlconv.h&gt;</p> <p>int _tmain(int argc, _TCHAR* argv[])<br> {<br> &nbsp;&nbsp;&nbsp;  char* s = &quot;sdfsdfssdv&quot;;<br> &nbsp;&nbsp;&nbsp;  int t = 10;<br> &nbsp;&nbsp;&nbsp;  printf(&quot;%s, %d\n&quot;, s, t);<br> &nbsp;&nbsp;&nbsp;  _tprintf_s(_T(&quot;%s, %d\n&quot;), CA2CT(s), t);<br> &nbsp;&nbsp;&nbsp;  return 0;<br> }</p> </td> </tr> </tbody> </table> </div> <p>正常情况下应该输出</p> <p>sdfsdfssdv, 10<br> sdfsdfssdv, 10</p> <p>但是，实际输出的却是</p> <p>sdfsdfssdv, 10<br> sdfsdfssdv, 6553715</p> <p>这很令人费解，尚未找到问题原因。</p> <p>如果把上述代码中的CA2CT(s)改成CA2CT(s).m_psz的话，程序恢复正常。请知情人士告诉俺咋回事……</p></div></p> <a href="http://hi.baidu.com/icexile/blog/item/d67cfbfd97818c4fd7887d5a.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/icexile/blog/category/visual%20c%2B%2B">visual c++</a>&nbsp;<a href="http://hi.baidu.com/icexile/blog/item/d67cfbfd97818c4fd7887d5a.html#comment">查看评论</a>]]></description>
        <pubDate>2009年09月22日 星期二  下午 06:24</pubDate>
        <category><![CDATA[visual c++]]></category>
        <author><![CDATA[Icexile]]></author>
		<guid>http://hi.baidu.com/icexile/blog/item/d67cfbfd97818c4fd7887d5a.html</guid>
</item>

<item>
        <title><![CDATA[【转】c中读取Lua的全局变量数组]]></title>
        <link><![CDATA[http://hi.baidu.com/icexile/blog/item/bae3cbde8798905e94ee37b7.html]]></link>
        <description><![CDATA[
		
		<p><div ><p>原帖：<a href="http://blog.csdn.net/SpiriTRinG/archive/2009/03/14/3990733.aspx">http://blog.csdn.net/SpiriTRinG/archive/2009/03/14/3990733.aspx</a></p> <p>配置实际上是非常简单的，添加好lib和头文件就ok了。</p> <p>注意如果您是使用动态库，需要配置dll，最好的方式是把dll放在编译目录下，</p> <p>这样发布您的程序就不会忘记这些杂七杂八的dll了。</p> <div> <table class="IcexileCode" border="1" cellspacing="-1" cellpadding="0" width="80%"> <tbody> <tr valign="top"> <td>  <p><span style="COLOR: rgb(255,0,0)">Lua文件</span>：luatext.lua</p> <p>----------------------------------------------------------------------------------</p> <p>gnum = 1</p> <p><br> background = {r=1, g=2, b=3}<br> <br> tab = {a=44 ,b=33 ,c=22,1, 2, 3, 4, 5, 6, 7, 8, 9, 0}</p> <p>----------------------------------------------------------------------------------</p> <p><span style="COLOR: rgb(255,0,0)">c文件</span>：lua.cpp</p> <p>----------------------------------------------------------------------------------</p> <p>#include &lt;stdio.h&gt;<br> #include &lt;iostream&gt;<br> #include &lt;stdarg.h&gt;<br> <br> #pragma comment(lib,&quot;lua51.lib&quot;)<br> <br> extern &quot;C&quot;<br> {<br> #include &quot;lua.h&quot;&nbsp;&nbsp;&nbsp;<br> #include &quot;lualib.h&quot;&nbsp;&nbsp;&nbsp;<br> #include &quot;lauxlib.h&quot;<br> }<br> using namespace std;<br> <br> lua_State *L;<br> <br> int getGlobal(lua_State *l,char * varname)<br> {<br> &nbsp;&nbsp;&nbsp;  static int count = 0;<br> &nbsp;&nbsp;&nbsp;  lua_getglobal(l, varname);<br> &nbsp;&nbsp;&nbsp;  return ++count;<br> }<br> <br> float getGlobalNumber(lua_State *l ,char * varname)<br> {<br> &nbsp;&nbsp;&nbsp;  return (float)lua_tonumber&nbsp;&nbsp;&nbsp;  (l, getGlobal(l, varname));<br> }<br> <br> <br> float getField (const char *key)<br> {<br> &nbsp;&nbsp;&nbsp;  float result = 0.0f;<br> &nbsp;&nbsp;&nbsp;  lua_pushstring(L, key);<br> &nbsp;&nbsp;&nbsp;  lua_gettable(L, -2);<br> &nbsp;&nbsp;&nbsp;  result = (float)lua_tonumber(L, -1);<br> &nbsp;&nbsp;&nbsp;  lua_pop(L, 1);<br> &nbsp;&nbsp;&nbsp;  return result;<br> }<br> <br> float getNumber (const lua_Number num)<br> {<br> &nbsp;&nbsp;&nbsp;  float result = 0.0f;<br> &nbsp;&nbsp;&nbsp;  lua_pushnumber(L, num);<br> &nbsp;&nbsp;&nbsp;  lua_gettable(L, -2);<br> &nbsp;&nbsp;&nbsp;  result = (float)lua_tonumber(L, -1);<br> &nbsp;&nbsp;&nbsp;  lua_pop(L, 1);<br> &nbsp;&nbsp;&nbsp;  return result;<br> }<br> <br> int main (void)<br> {<br> ////////////////////////////////////////////////////////////////<br> <br> &nbsp;&nbsp;&nbsp;  L = lua_open();<br> &nbsp;&nbsp;&nbsp;  luaL_openlibs (L);<br> &nbsp;&nbsp;&nbsp;  luaL_loadfile(L, &quot;luatext.lua&quot;);<br> &nbsp;&nbsp;&nbsp;  lua_pcall(L, 0, 0, 0);<br> &nbsp;&nbsp;&nbsp;<br> &nbsp;&nbsp;&nbsp;  lua_getglobal(L, &quot;background&quot;);<br> &nbsp;&nbsp;&nbsp;  cout&lt;&lt;getField(&quot;r&quot;)&lt;&lt;endl;<br> &nbsp;&nbsp;&nbsp;  cout&lt;&lt;getField(&quot;g&quot;)&lt;&lt;endl;<br> &nbsp;&nbsp;&nbsp;  cout&lt;&lt;getField(&quot;b&quot;)&lt;&lt;endl;<br> <br> &nbsp;&nbsp;&nbsp;  lua_getglobal(L, &quot;tab&quot;);<br> &nbsp;&nbsp;&nbsp;  cout&lt;&lt;getField(&quot;a&quot;)&lt;&lt;endl;<br> &nbsp;&nbsp;&nbsp;  cout&lt;&lt;getField(&quot;b&quot;)&lt;&lt;endl;<br> &nbsp;&nbsp;&nbsp;  cout&lt;&lt;getField(&quot;c&quot;)&lt;&lt;endl;<br> &nbsp;&nbsp;&nbsp;  for(int i =1 ; i&lt;=10 ; i++)<br> &nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;  cout&lt;&lt;getNumber(i)&lt;&lt;endl;<br> <br> <br> ///////////////////////////////////////////////////////////////<br> &nbsp;&nbsp;&nbsp;  lua_close(L);<br> &nbsp;&nbsp;&nbsp;  getchar();<br> &nbsp;&nbsp;&nbsp;  return 0;<br> }</p> </td> </tr> </tbody> </table> </div></div></p> <a href="http://hi.baidu.com/icexile/blog/item/bae3cbde8798905e94ee37b7.html">阅读全文</a>
		
		<br/><b>类别：</b><a href="http://hi.baidu.com/icexile/blog/category/%BD%C5%B1%BE">脚本</a>&nbsp;<a href="http://hi.baidu.com/icexile/blog/item/bae3cbde8798905e94ee37b7.html#comment">查看评论</a>]]></description>
        <pubDate>2009年09月21日 星期一  下午 06:40</pubDate>
        <category><![CDATA[脚本]]></category>
        <author><![CDATA[Icexile]]></author>
		<guid>http://hi.baidu.com/icexile/blog/item/bae3cbde8798905e94ee37b7.html</guid>
</item>


</channel>
</rss>