<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Wut I am &#187; Development</title>
	<atom:link href="http://wutiam.net/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>http://wutiam.net</link>
	<description>I&#039;m islet8, I&#039;m what I am</description>
	<lastBuildDate>Wed, 25 Jan 2012 14:11:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>游戏引擎设计 之 内存管理框架</title>
		<link>http://wutiam.net/2011/10/game-engine-design-memory-management-framework/</link>
		<comments>http://wutiam.net/2011/10/game-engine-design-memory-management-framework/#comments</comments>
		<pubDate>Mon, 17 Oct 2011 12:46:31 +0000</pubDate>
		<dc:creator>islet8</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[游戏开发]]></category>
		<category><![CDATA[游戏引擎]]></category>

		<guid isPermaLink="false">http://wutiam.net/?p=14</guid>
		<description><![CDATA[内存管理对于大型游戏来说是至关重要的一环，这里我们所说的“内存”指的是动态分配的内存。一个好的内存管理框架，能显著提升程序执行效率，也能大大提高内存问题的调试效率。所以，我们设计内存管理框架时必须能够满足以下两大需求： 自定义内存分配器 malloc/free（包括间接由new/delete等调过来的）等函数本身的开销其实并不大，但由于其功能太过基础了，没有任何策略可言，从而导致反复分配释放带来的开销、大量内存碎片以及多线程内存分配引起的效率问题。所以自定义一个高效的内存分配器就显得必不可少了，对于一般情况，我们可以使用 nedmalloc、jemalloc 等第三方多线程内存分配器，也可以根据具体需求自己实现一套（例如 Nebula3 中的内存池以及 Heap 对象机制），甚至是基于栈的动态内存分配。而具体的内存分配/释放策略是另一个话题了，以后新开一篇讨论。 内存统计及内存泄漏跟踪 虽然 CRT 有 dump 内存泄漏的功能，但最大的问题就在于——仅限于 DEBUG 环境下，而游戏由于其实时计算的复杂性，在后期很多情况下开 DEBUG 模式已经无法满足正常调试的需求了，所以 Release with debug info 模式其实才是我们更常用的，这样我们就必须自己实现内存统计及泄漏跟踪的功能，甚至提供对动态内存泄漏（运行时大量已无用的内存未释放，直到游戏退出时才一并释放，最常见的就是由智能指针引起的动态内存泄漏）的检查。 先说说第一点，我们需要把 malloc/free 和 new/delete 的分配/释放部分重定向到我们自己的分配/释放函数（handler）里，然后在我们的函数里调用指定的内存分配器的分配/释放函数（allocator），这就完成了。 第二点，正好可以利用第一点定义出来的我们自己的分配/释放函数，除了调用分配器之外，再通知内存分配统计模块更新统计信息（记录新分配的内存的相关信息或删掉相关的信息），这样内存分配统计模块就完成了统计和泄漏报告两大功能了。 来看看具体的伪码吧： 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 [...]
Related posts:<ul>
<li><a href='http://wutiam.net/2010/03/ingenious-usage-of-do-while-0/' rel='bookmark' title='do...while(0) 的妙用'>do...while(0) 的妙用</a></li>
<li><a href='http://wutiam.net/2010/09/lower_bound-strange-compiling-error-in-ms-stl/' rel='bookmark' title='微软 STL lower_bound() 在 DEBUG 下的诡异编译错误'>微软 STL lower_bound() 在 DEBUG 下的诡异编译错误</a></li>
<li><a href='http://wutiam.net/2006/08/const-int-ptr/' rel='bookmark' title='(const int * i || int const * i) &amp;&amp; int * const i'>(const int * i || int const * i) &#038;& int * const i</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>内存管理对于大型游戏来说是至关重要的一环，这里我们所说的“内存”指的是<strong>动态分配</strong>的内存。一个好的内存管理框架，能显著提升程序执行效率，也能大大提高内存问题的调试效率。所以，我们设计内存管理框架时必须能够满足以下两大需求：</p>
<ol>
<li>自定义内存分配器</li>
<p>malloc/free（包括间接由new/delete等调过来的）等函数本身的开销其实并不大，但由于其功能太过基础了，没有任何策略可言，从而导致反复分配释放带来的开销、大量内存碎片以及多线程内存分配引起的效率问题。所以自定义一个高效的内存分配器就显得必不可少了，对于一般情况，我们可以使用 <a href="http://www.nedprod.com/programs/portable/nedmalloc/" target="_blank">nedmalloc</a>、<a href="http://www.canonware.com/jemalloc/" target="_blank">jemalloc</a> 等第三方多线程内存分配器，也可以根据具体需求自己实现一套（例如 <a href="http://code.google.com/p/nebula3/" target="_blank">Nebula3</a> 中的内存池以及 Heap 对象机制），甚至是<a title="Stack-based memory allocation" href="http://en.wikipedia.org/wiki/Stack-based_memory_allocation" target="_blank">基于栈的动态内存分配</a>。而具体的内存分配/释放策略是另一个话题了，以后新开一篇讨论。</p>
<li>内存统计及内存泄漏跟踪</li>
<p>虽然 CRT 有 dump 内存泄漏的功能，但最大的问题就在于——仅限于 DEBUG 环境下，而游戏由于其实时计算的复杂性，在后期很多情况下开 DEBUG 模式已经无法满足正常调试的需求了，所以 Release with debug info 模式其实才是我们更常用的，这样我们就必须自己实现内存统计及泄漏跟踪的功能，甚至提供对动态内存泄漏（运行时大量已无用的内存未释放，直到游戏退出时才一并释放，最常见的就是由智能指针引起的动态内存泄漏）的检查。
</ol>
<p><span id="more-14"></span>先说说第一点，我们需要把 malloc/free 和 new/delete 的分配/释放部分重定向到我们自己的分配/释放函数（handler）里，然后在我们的函数里调用指定的内存分配器的分配/释放函数（allocator），这就完成了。</p>
<p>第二点，正好可以利用第一点定义出来的我们自己的分配/释放函数，除了调用分配器之外，再通知内存分配统计模块更新统计信息（记录新分配的内存的相关信息或删掉相关的信息），这样内存分配统计模块就完成了统计和泄漏报告两大功能了。</p>
<p>来看看具体的伪码吧：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #666666;">// Handle allocation/deallocation</span>
<span style="color: #0000ff;">class</span> AllocationHandler
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
<span style="color: #339900;">#ifdef MEMORY_STATS</span>
    <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> Allocate<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> size, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> fileName, <span style="color: #0000ff;">int</span> lineNum, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> funcName<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        AllocStats<span style="color: #008080;">::</span><span style="color: #007788;">Alloc</span><span style="color: #008000;">&#40;</span>size, fileName, lineNum, funcName<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">return</span> Allocator<span style="color: #008080;">::</span><span style="color: #007788;">Allocate</span><span style="color: #008000;">&#40;</span>size<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #339900;">#else</span>
    <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> Allocate<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> size<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">return</span> Allocator<span style="color: #008080;">::</span><span style="color: #007788;">Allocate</span><span style="color: #008000;">&#40;</span>size<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #339900;">#endif // MEMORY_STATS</span>
&nbsp;
    <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> Deallocate<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> ptr<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        Allocator<span style="color: #008080;">::</span><span style="color: #007788;">Deallocate</span><span style="color: #008000;">&#40;</span>ptr<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #666666;">// re-define to your own allocator</span>
    <span style="color: #0000ff;">typedef</span> DefaultAllocator Allocator<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #666666;">// Allocator using default CRT malloc</span>
<span style="color: #0000ff;">class</span> MM_DefaultAllocator
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> Allocate<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> size<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">malloc</span><span style="color: #008000;">&#40;</span>size<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> Deallocate<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> ptr<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000dd;">free</span><span style="color: #008000;">&#40;</span>ptr<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>基本原理非常简单，但“现实总是残酷的”！为了方便的传入调试信息（__FILE__、__LINE__、 __FUNCTION__ 等），我们使用宏来定义我们自己的分配函数：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#ifdef MEMORY_STATS</span>
<span style="color: #339900;">#define MALLOC(size)        AllocationHandler::Allocate(size, __FILE__, __LINE__, __FUNCTION__)</span>
<span style="color: #339900;">#define ALLOC(T, count)     static_cast&lt;T*&gt;(AllocationHandler::Allocate(sizeof(T)*(count), __FILE__, __LINE__, __FUNCTION__))</span>
<span style="color: #339900;">#define T_FREE(ptr)         AllocationHandler::Deallocate(ptr)</span>
<span style="color: #339900;">#else</span>
<span style="color: #339900;">#define MALLOC(size)        AllocationHandler::Allocate(size)</span>
<span style="color: #339900;">#define ALLOC(T, count)     (T*)AllocationHandler::Allocate(sizeof(T)*(count))</span>
<span style="color: #339900;">#define FREE(ptr)           AllocationHandler::Deallocate(ptr)</span>
<span style="color: #339900;">#endif // MEMORY_STATS</span></pre></td></tr></table></div>

<p>很好，可是 new/delete 呢？我也很想一起把它们定义出来，就像这样：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #ff0000; font-style: italic;">/*
#define GE_NEW(type)                new(__FILE__, __LINE__, __FUNCTION__) type
#define GE_DELETE(ptr)              delete ptr
#define GE_NEW_ARRAY(type, count)   new(__FILE__, __LINE__, __FUNCTION__) type[count]
#define GE_DELETE_ARRAY(ptr)        delete[] ptr
&nbsp;
inline void* operator new(size_t size, const char* fileName, int lineNum, const char* funcName)
{
    return AllocationHandler::Allocate(size, fileName, lineNum, funcName);
}
inline void operator delete(void* ptr)
{
    return AllocationHandler::Deallocate(ptr);
}
// only called if there is an exception in corresponding 'new'
inline void operator delete(void* ptr, const char*, int, const char*)
{
    return AllocationHandler::Deallocate(ptr);
}
inline void* operator new[](size_t size, const char* fileName, int lineNum, const char* funcName)
{
    return AllocationHandler::Allocate(size, fileName, lineNum, funcName);
}
inline void operator delete[](void* ptr)
{
    return AllocationHandler::Deallocate(ptr);
}
// only called if there is an exception in corresponding 'new'
inline void operator delete[](void* ptr, const char*, int, const char*)
{
    return AllocationHandler::Deallocate(ptr);
}
*/</span></pre></td></tr></table></div>

<p>通过重定义全局的 new/delete operators 来重定向，看起来很统一、很完美。可是，除了程序自己的所有代码的 new/delete 被重定向了以外，连第三方库里的所有 new/delete 操作也都被重定向到我们自己的分配器来了（这里所说的第三方库指的是以源码方式发布并合入我们的工程的），而这些第三方库里的内存分配被我们接管后，可能会导致一些意想不到的异常结果。此路不通。</p>
<p>既然不能替换全局的 new/delete 操作符，但至少可以替换掉一部分 class 的 new/delete 操作符吧，即，凡是从 MemoryObject 继承的子类，将其 new/delete 都接管到我们的分配器上（这也是 <a href="http://www.ogre3d.org/" target="_blank">ORGE</a> 和 <a href="http://www.gamebryo.com/" target="_blank">Gamebryo</a> 所采用的方法）：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#ifdef MEMORY_STATS</span>
<span style="color: #339900;">#define NEW(T)          new(__FILE__, __LINE__, __FUNCTION__) T</span>
<span style="color: #339900;">#else</span>
<span style="color: #339900;">#define NEW(T)          new T</span>
<span style="color: #339900;">#endif // MEMORY_STATS</span>
<span style="color: #339900;">#define T_DELETE(ptr)   delete ptr</span>
&nbsp;
<span style="color: #666666;">// Override MemoryObject-derived classes' new/delete operators to redirect to AllocationHandler</span>
<span style="color: #339900;">#ifdef MEMORY_STATS</span>
<span style="color: #0000ff;">class</span> MemoryObject
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> operator <span style="color: #0000dd;">new</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">size_t</span> size, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> fileName, <span style="color: #0000ff;">int</span> lineNum, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> funcName<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">void</span> operator <span style="color: #0000dd;">delete</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> ptr<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #666666;">// only called if there is an exception in corresponding 'new'</span>
    <span style="color: #0000ff;">void</span> operator <span style="color: #0000dd;">delete</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> ptr, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span>, <span style="color: #0000ff;">int</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> MemoryObject<span style="color: #008080;">::</span><span style="color: #007788;">operator</span> <span style="color: #0000dd;">new</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">size_t</span> size, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> fileName, <span style="color: #0000ff;">int</span> lineNum, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> funcName<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> AllocationHandler<span style="color: #008080;">::</span><span style="color: #007788;">Allocate</span><span style="color: #008000;">&#40;</span>size, fileName, lineNum, funcName<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">void</span> MemoryObject<span style="color: #008080;">::</span><span style="color: #007788;">operator</span> <span style="color: #0000dd;">delete</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> ptr<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    AllocationHandler<span style="color: #008080;">::</span><span style="color: #007788;">Deallocate</span><span style="color: #008000;">&#40;</span>ptr<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">void</span> MemoryObject<span style="color: #008080;">::</span><span style="color: #007788;">operator</span> <span style="color: #0000dd;">delete</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> ptr, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span>, <span style="color: #0000ff;">int</span>, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    AllocationHandler<span style="color: #008080;">::</span><span style="color: #007788;">Deallocate</span><span style="color: #008000;">&#40;</span>ptr<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #339900;">#else</span>
<span style="color: #0000ff;">class</span> MemoryObject
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> operator <span style="color: #0000dd;">new</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">size_t</span> size<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">void</span> operator <span style="color: #0000dd;">delete</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> ptr<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> MemoryObject<span style="color: #008080;">::</span><span style="color: #007788;">operator</span> <span style="color: #0000dd;">new</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">size_t</span> size<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> AllocationHandler<span style="color: #008080;">::</span><span style="color: #007788;">Allocate</span><span style="color: #008000;">&#40;</span>size<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">void</span> MemoryObject<span style="color: #008080;">::</span><span style="color: #007788;">operator</span> <span style="color: #0000dd;">delete</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> ptr<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    AllocationHandler<span style="color: #008080;">::</span><span style="color: #007788;">Deallocate</span><span style="color: #008000;">&#40;</span>ptr<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
<span style="color: #339900;">#endif // MEMORY_STATS</span></pre></td></tr></table></div>

<p>然而，毕竟还有那么多 <a href="http://en.wikipedia.org/wiki/Plain_old_data_structure" target="_blank">POD</a> 类型、自定义的简单结构体的数据，都用 MemoryObject 包起来既不现实又没效率，那只能为它们再单独制定一套 new/delete 策略了，类似 OGRE 的实现：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#ifdef MEMORY_STATS</span>
<span style="color: #339900;">#define EXTERNAL_NEW(T)     new(AllocationHandler::Allocate(sizeof(T), __FILE__, __LINE__, __FUNCTION__)) T</span>
<span style="color: #339900;">#else</span>
<span style="color: #339900;">#define EXTERNAL_NEW(T)     new(AllocationHandler::Allocate(sizeof(T))) T</span>
<span style="color: #339900;">#endif // MEMORY_STATS</span>
<span style="color: #339900;">#define EXTERNAL_DELETE(ptr, T) if (ptr != NULL_PTR) { (ptr)-&gt;~T(); AllocationHandler::Deallocate(ptr); }</span></pre></td></tr></table></div>

<p>但这里我们去掉了对数组的支持，原因是一方面自定义数组的 new/delete 处理代码比较丑陋，另一方面也不支持多维数组的创建，而且我们对引擎设计的其中一条底线就是禁止上层应用直接使用原生数组（越界引起的各种崩溃，太让人崩溃了），要玩数组，用我们自己封的数组对象吧。顺便说一句，说实话我个人觉得 OGRE 的内存分配 category 和 policy 有过度设计的嫌疑，而且其分类和策略的设计并不能为多分配器提供支持，所以我直接让分配请求和分配器对接了。未来如果需要对不同的对象采用不同的分配器，可以考虑 <a href="http://heliumproject.org/" target="_blank">Helium</a> 的设计思路，通过模板将分配器直接传入类定义。</p>
<p>好了，内存管理的框架设计就是这样，看起来很简单，但为什么设计成了这样，也许只有等你也走过一遍才会有深刻的理解，也许你的需求，可以产生更优秀的框架。</p>
<p>Related posts:<ul>
<li><a href='http://wutiam.net/2010/03/ingenious-usage-of-do-while-0/' rel='bookmark' title='do...while(0) 的妙用'>do...while(0) 的妙用</a></li>
<li><a href='http://wutiam.net/2010/09/lower_bound-strange-compiling-error-in-ms-stl/' rel='bookmark' title='微软 STL lower_bound() 在 DEBUG 下的诡异编译错误'>微软 STL lower_bound() 在 DEBUG 下的诡异编译错误</a></li>
<li><a href='http://wutiam.net/2006/08/const-int-ptr/' rel='bookmark' title='(const int * i || int const * i) &amp;&amp; int * const i'>(const int * i || int const * i) &#038;& int * const i</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://wutiam.net/2011/10/game-engine-design-memory-management-framework/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>代码之初，性本丑？(下)</title>
		<link>http://wutiam.net/2011/08/ugly-code-at-birth-part3/</link>
		<comments>http://wutiam.net/2011/08/ugly-code-at-birth-part3/#comments</comments>
		<pubDate>Sat, 27 Aug 2011 03:49:55 +0000</pubDate>
		<dc:creator>islet8</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c++]]></category>

		<guid isPermaLink="false">http://wutiam.net/?p=154</guid>
		<description><![CDATA[《代码之丑（六）——分家的声明和使用》 变量声明的就近原则，除了该文中提到的几点好处之外，还有一点就是能够提高发现声明了却未使用的变量的概率。别小看这个问题，以为编译器会给优化掉，我就碰到过一坨很烂的代码，这个函数里做了大量的计算，比如先经过复杂计算得到 a，然后 a 经过计算得到 b，b 再经过计算得到 c，c 再计算后得到 d，在一团乱麻的代码里，谁也没发现，其实 d 根本没被用到，函数最后直接拿 e 返回了…… 《代码之丑（七）——你的语言》 这篇有点各抒己见的意思，不过我觉得有一点是明确的，学一门语言，主要是学习它的思维方式，而不仅仅学会语法就算完了。至于具体怎么用，这是每个 team 自己定编码规范的事了。 《代码之丑（八）——不一致的困惑》 这个例子都老的快成寓言故事了，不过就算如此，我们还是有同学把四种字符串类型随心所欲地混用的代码，其中一种是 STL 的、一种是 MFC 的、一种是第三方引擎库的、一种是他不知道从哪个网页里抄来的。原因也正如该文里提到的，每种字符串类型都有他想用的功能，但有时又缺点什么。于是乎 ，呵呵，debug 这样的代码是痛苦的，大量的类型转换，大量的字符串内存分配，仅仅是为了满足他不同函数间定义的形参或返回值类型的不同。 我觉得，不仅仅是软件设计要尽可能的保证一致性和唯一性（就像《人月神话》中所说的外科手术团队模式，也是我非常赞同的），编码等具体事物也需要有一致性，这不仅仅是效率和可维护性的问题，而是一个人、一个团队的态度问题，一个“大心脏”的程序员（见第五篇），他的代码能给谁带来安全感？ 《代码之丑（九）——退让的缩进》 缩进是个永恒的话题。两个空格、四个空格、一个 tab，{} 跟上一层对齐还是跟下一层对齐，其实这些都不重要，重要的是明白缩进是为了什么？可读性！当然是可读性！就算 Python 的缩进含有控制的功能，那也是因为看明白了可读性的重要性。 从理论上讲，一个函数不能太长，一个条件也不能太长，一个循环更不能太长，所以缩进也不能有太多层，谁不希望是这样呢？大部分的冗长代码确实可以通过改变设计来拆分甚至是消除丑陋，可是现实总是残酷的（比纸上谈兵残酷得多），有些情况从逻辑上讲已经是原子操作的了，但从代码角度却依然有大量跳转计算和前后依赖，这就存在一个如何折衷的问题了。把连续依赖的 10 小段代码分别挪到 10 个独立的函数中去？想想假如在看书的时候全文都是“参见 XX 页 xx 段”的情况，这样的书有人爱看么？ 所以，缩进不是可读性的唯一，连贯的思路也一样非常重要。 《代码之丑（十）——条件编译那些事儿​》 该文基本都说得差不多了，这也是这几年比较流行的改进方法，最近看了几个引擎的代码，确实舒服多了。但有一点要注意，是否拆分到文件，还是得看具体的功能是否强依赖于平台，如果依赖度较低，虽然拆到独立文件后可读性很高了，但维护性却大大降低了。为什么？DRY —— Don't Repeat Yourself！ 后话 说得够多了，类似《代码大全》上的观点本来没必要那么多人反复的说。但是，就算已经有那么多人反复的说过了，工作中大部分人还是坚定地认为（至少潜意识里认为），“程序么，能跑就好了，你看，功能好得很呢”。嗨！真的是大部分人呢。所以只好再多说一次，多说一次，总可能会多影响一个人，也是好事。 费那么大劲说，费那么大劲做，图什么，无非是想要明天的日子好过一些。说来说去，还是一句老话：性格决定命运，气度决定格局，细节决定成败，态度决定一切。 Related posts: 代码之初，性本丑？(中) [...]
Related posts:<ul>
<li><a href='http://wutiam.net/2011/01/ugly-code-at-birth-part2/' rel='bookmark' title='代码之初，性本丑？(中)'>代码之初，性本丑？(中)</a></li>
<li><a href='http://wutiam.net/2010/12/ugly-code-at-birth-part1/' rel='bookmark' title='代码之初，性本丑？(上)'>代码之初，性本丑？(上)</a></li>
<li><a href='http://wutiam.net/2009/05/forward-declaration-or-include/' rel='bookmark' title='用 前置声明，还是用 #include？'>用 前置声明，还是用 #include？</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p><strong>《<a href="http://www.infoq.com/cn/news/2010/11/ugly-code-6" target="_blank">代码之丑（六）——分家的声明和使用</a>》</strong></p>
<p>变量声明的就近原则，除了该文中提到的几点好处之外，还有一点就是能够提高发现声明了却未使用的变量的概率。别小看这个问题，以为编译器会给优化掉，我就碰到过一坨很烂的代码，这个函数里做了大量的计算，比如先经过复杂计算得到 a，然后 a 经过计算得到 b，b 再经过计算得到 c，c 再计算后得到 d，在一团乱麻的代码里，谁也没发现，其实 d 根本没被用到，函数最后直接拿 e 返回了……</p>
<p><strong>《<a href="http://www.infoq.com/cn/news/2010/12/ugly-code-7" target="_blank">代码之丑（七）——你的语言</a>》</strong></p>
<p>这篇有点各抒己见的意思，不过我觉得有一点是明确的，学一门语言，主要是学习它的思维方式，而不仅仅学会语法就算完了。至于具体怎么用，这是每个 team 自己定编码规范的事了。</p>
<p><span id="more-154"></span><strong>《<a href="http://www.infoq.com/cn/news/2010/12/ugly-code-8" target="_blank">代码之丑（八）——不一致的困惑</a>》</strong></p>
<p>这个例子都老的快成寓言故事了，不过就算如此，我们还是有同学把四种字符串类型随心所欲地混用的代码，其中一种是 STL 的、一种是 MFC 的、一种是第三方引擎库的、一种是他不知道从哪个网页里抄来的。原因也正如该文里提到的，每种字符串类型都有他想用的功能，但有时又缺点什么。于是乎 ，呵呵，debug 这样的代码是痛苦的，大量的类型转换，大量的字符串内存分配，仅仅是为了满足他不同函数间定义的形参或返回值类型的不同。</p>
<p>我觉得，不仅仅是软件设计要尽可能的保证一致性和唯一性（就像《人月神话》中所说的外科手术团队模式，也是我非常赞同的），编码等具体事物也需要有一致性，这不仅仅是效率和可维护性的问题，而是一个人、一个团队的态度问题，一个“大心脏”的程序员（见第五篇），他的代码能给谁带来安全感？</p>
<p><strong>《<a href="http://www.infoq.com/cn/news/2010/12/ugly-code-9" target="_blank">代码之丑（九）——退让的缩进</a>》</strong></p>
<p>缩进是个永恒的话题。两个空格、四个空格、一个 tab，{} 跟上一层对齐还是跟下一层对齐，其实这些都不重要，重要的是明白缩进是为了什么？可读性！当然是可读性！就算 Python 的缩进含有控制的功能，那也是因为看明白了可读性的重要性。</p>
<p>从理论上讲，一个函数不能太长，一个条件也不能太长，一个循环更不能太长，所以缩进也不能有太多层，谁不希望是这样呢？大部分的冗长代码确实可以通过改变设计来拆分甚至是消除丑陋，可是现实总是残酷的（比纸上谈兵残酷得多），有些情况从逻辑上讲已经是原子操作的了，但从代码角度却依然有大量跳转计算和前后依赖，这就存在一个如何折衷的问题了。把连续依赖的 10 小段代码分别挪到 10 个独立的函数中去？想想假如在看书的时候全文都是“参见 XX 页 xx 段”的情况，这样的书有人爱看么？</p>
<p>所以，缩进不是可读性的唯一，连贯的思路也一样非常重要。</p>
<p><strong>《<a href="http://www.infoq.com/cn/news/2010/12/ugly-code-10" target="_blank">代码之丑（十）——条件编译那些事儿​</a>》</strong></p>
<p>该文基本都说得差不多了，这也是这几年比较流行的改进方法，最近看了几个引擎的代码，确实舒服多了。但有一点要注意，是否拆分到文件，还是得看具体的功能是否强依赖于平台，如果依赖度较低，虽然拆到独立文件后可读性很高了，但维护性却大大降低了。为什么？DRY —— Don't Repeat Yourself！</p>
<p><strong>后话</strong></p>
<p>说得够多了，类似《代码大全》上的观点本来没必要那么多人反复的说。但是，就算已经有那么多人反复的说过了，工作中大部分人还是坚定地认为（至少潜意识里认为），“程序么，能跑就好了，你看，功能好得很呢”。嗨！真的是大部分人呢。所以只好再多说一次，多说一次，总可能会多影响一个人，也是好事。</p>
<p>费那么大劲说，费那么大劲做，图什么，无非是想要明天的日子好过一些。说来说去，还是一句老话：性格决定命运，气度决定格局，细节决定成败，<strong>态度决定一切</strong>。</p>
<p>Related posts:<ul>
<li><a href='http://wutiam.net/2011/01/ugly-code-at-birth-part2/' rel='bookmark' title='代码之初，性本丑？(中)'>代码之初，性本丑？(中)</a></li>
<li><a href='http://wutiam.net/2010/12/ugly-code-at-birth-part1/' rel='bookmark' title='代码之初，性本丑？(上)'>代码之初，性本丑？(上)</a></li>
<li><a href='http://wutiam.net/2009/05/forward-declaration-or-include/' rel='bookmark' title='用 前置声明，还是用 #include？'>用 前置声明，还是用 #include？</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://wutiam.net/2011/08/ugly-code-at-birth-part3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>代码之初，性本丑？(中)</title>
		<link>http://wutiam.net/2011/01/ugly-code-at-birth-part2/</link>
		<comments>http://wutiam.net/2011/01/ugly-code-at-birth-part2/#comments</comments>
		<pubDate>Sat, 08 Jan 2011 08:58:32 +0000</pubDate>
		<dc:creator>islet8</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c++]]></category>

		<guid isPermaLink="false">http://wutiam.net/?p=144</guid>
		<description><![CDATA[《代码之丑（三）——switch陷阱》 可能是因为篇幅关系，这篇文章里的例子不够有代表性，而且还有越改越没有可读性和可维护性之嫌。曾经我在公司的一个比较有历史的程序里看到过一段伟岸的 switch/case 代码，每个 case 下的代码各不相同且长短不一也就算了，可能你无法想象的是，它里面竟然有几千个 case，总共 10000+ 行的代码！你没看错，一个函数一万多行！这就是从一开始放任 switch 陷阱，经过漫长地演化得到的后果。 其实我并不认为该把 switch/case 当作唯恐避之不及的恶魔，它只是一把双刃剑，就像没必要一味地反对使用 if 一样。在正确的环境下正确使用它的话，只会提高可读性，但如果滥用它（就像 C++ 很多其他特性那样），那的确是一场噩梦。 对于本身结构很简单的逻辑，使用 switch/case 能很好地保持其可读性（显然比一堆的 if/else 好，更不用说多态了），而且也正因为其逻辑简单，条件不多，也不会对系统性能产生明显影响（代码并非越短越快就越好，它首先是给人看的，顺便附带了能让机器执行的功能）。而对于我上面提到的超大的逻辑结构，倒是可以用多态或者状态机来解决，定位问题显然会方便不少（假如这个逻辑架构本身没法改变的话）。 《代码之丑（四）——代码找茬游戏》 “代码重复是 bug 之母”，没错，这就是传说中的 DRY 原则（Don't Repeat Yourself）。可悲的是，现实开发中，重复的代码比比皆是，无论是大拿还是小菜鸟，因为这是人的本性，在拷贝代码的时候说服自己，写完功能就把这儿重构掉，然而一旦功能完成，就不想再动这块代码了，否则做完了重构还得重新测一遍，太麻烦了。三个月后，因为业务逻辑的改动或者 bugs，另一位同事只改了其中一个代码的拷贝（他可不知道你的这些小秘密，甚至其实你自己也已经不记得了），完蛋了，又要花上一整天的时间来查到底出了什么事。可有几个人能坚持为以后的自己负责呢？“说不定再也不会暴露出来，先管它呢”。 唉。 人会犯错，想偷懒，本来都不可怕。对于大多数程序员，引入交叉 code review 机制，真是一个不错的选择，毕竟总是做得比别人差是很难堪的。但对于少数缺乏羞耻心的人来说，真没什么好办法，如果我是老板，别让我的团队被一颗老鼠屎糟蹋了。 《代码之丑（五）——不受欢迎的大心脏》 先局限在该文的例子说说，这个代码的问题得根据其真正的用意来定。如果它真的是为了克隆 oldRule 的所有属性并加入到规则池中去，那更好的做法应该是为 ColdRule 类提供一个拷贝构造函数： rules-&#62;Add&#40;new ColdRule&#40;oldRule&#41;&#41;; 能封装到自己内部的操作为什么要让外面了解这么多细节呢。但如果它的目的只是把 oldRule 中的一部分属性设给新的 rule，然后“可能”还要做些额外的设置（或者只是保留构造函数中的初始化设置），那就又得斟酌有没有必要提出一个公共函数来封装这份操作，以及这个函数是放在类内呢还是放到一个公共文件里了。 这就是我想说的，写代码很大条的确不是个受欢迎的性格，但有些代码的业务逻辑实在太繁琐了，它就是需要几十个步骤来完成，每个步骤还会有若干个分支，而这本身又只是一个很小的功能点（比如读取 DDS 图片文件头），为了代码“优雅”所付出的成本远高于其价值，那这样的重构是否还有必要呢？我个人认为很没有必要，倒不如花点小力气，写些注释，加些换行，把这块又长又复杂的代码弄得阅读起来顺溜些，总比把各个小秘密藏得到处都是好多了。 Related posts: 代码之初，性本丑？(下) [...]
Related posts:<ul>
<li><a href='http://wutiam.net/2011/08/ugly-code-at-birth-part3/' rel='bookmark' title='代码之初，性本丑？(下)'>代码之初，性本丑？(下)</a></li>
<li><a href='http://wutiam.net/2010/12/ugly-code-at-birth-part1/' rel='bookmark' title='代码之初，性本丑？(上)'>代码之初，性本丑？(上)</a></li>
<li><a href='http://wutiam.net/2009/05/forward-declaration-or-include/' rel='bookmark' title='用 前置声明，还是用 #include？'>用 前置声明，还是用 #include？</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p><strong>《<a href="http://www.infoq.com/cn/news/2010/11/ugly-code-3">代码之丑（三）——switch陷阱</a>》</strong></p>
<p>可能是因为篇幅关系，这篇文章里的例子不够有代表性，而且还有越改越没有可读性和可维护性之嫌。曾经我在公司的一个比较有历史的程序里看到过一段伟岸的 switch/case 代码，每个 case 下的代码各不相同且长短不一也就算了，可能你无法想象的是，它里面竟然有几千个 case，总共 10000+ 行的代码！你没看错，一个函数<strong>一万多</strong>行！这就是从一开始放任 switch 陷阱，经过漫长地演化得到的后果。</p>
<p>其实我并不认为该把 switch/case 当作唯恐避之不及的恶魔，它只是一把双刃剑，就像没必要一味地<a title="The Anti-IF Campaign" href="http://www.antiifcampaign.com/">反对使用 if</a> 一样。在正确的环境下正确使用它的话，只会提高可读性，但如果滥用它（就像 C++ 很多其他特性那样），那的确是一场噩梦。</p>
<p>对于本身结构很简单的逻辑，使用 switch/case 能很好地保持其可读性（显然比一堆的 if/else 好，更不用说多态了），而且也正因为其逻辑简单，条件不多，也不会对系统性能产生明显影响（代码并非越短越快就越好，它首先是给人看的，顺便附带了能让机器执行的功能）。而对于我上面提到的超大的逻辑结构，倒是可以用多态或者状态机来解决，定位问题显然会方便不少（假如这个逻辑架构本身没法改变的话）。</p>
<p><span id="more-144"></span><strong>《<a href="http://www.infoq.com/cn/news/2010/11/ugly-code-4">代码之丑（四）——代码找茬游戏</a>》</strong></p>
<p>“代码重复是 bug 之母”，没错，这就是传说中的 <a title="Don't repeat yourself" href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a> 原则（Don't Repeat Yourself）。可悲的是，现实开发中，重复的代码比比皆是，无论是大拿还是小菜鸟，因为这是人的本性，在拷贝代码的时候说服自己，写完功能就把这儿重构掉，然而一旦功能完成，就不想再动这块代码了，否则做完了重构还得重新测一遍，太麻烦了。三个月后，因为业务逻辑的改动或者 bugs，另一位同事只改了其中一个代码的拷贝（他可不知道你的这些小秘密，甚至其实你自己也已经不记得了），完蛋了，又要花上一整天的时间来查到底出了什么事。可有几个人能坚持为以后的自己负责呢？“说不定再也不会暴露出来，先管它呢”。</p>
<p>唉。</p>
<p>人会犯错，想偷懒，本来都不可怕。对于大多数程序员，引入交叉 code review 机制，真是一个不错的选择，毕竟总是做得比别人差是很难堪的。但对于少数缺乏羞耻心的人来说，真没什么好办法，如果我是老板，别让我的团队被一颗老鼠屎糟蹋了。</p>
<p><strong>《<a href="http://www.infoq.com/cn/news/2010/11/ugly-code-5">代码之丑（五）——不受欢迎的大心脏</a>》</strong></p>
<p>先局限在该文的例子说说，这个代码的问题得根据其真正的用意来定。如果它真的是为了克隆 oldRule 的所有属性并加入到规则池中去，那更好的做法应该是为 ColdRule 类提供一个拷贝构造函数：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">rules<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>Add<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">new</span> ColdRule<span style="color: #008000;">&#40;</span>oldRule<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>能封装到自己内部的操作为什么要让外面了解这么多细节呢。但如果它的目的只是把 oldRule 中的一部分属性设给新的 rule，然后“可能”还要做些额外的设置（或者只是保留构造函数中的初始化设置），那就又得斟酌有没有必要提出一个公共函数来封装这份操作，以及这个函数是放在类内呢还是放到一个公共文件里了。</p>
<p>这就是我想说的，写代码很大条的确不是个受欢迎的性格，但有些代码的业务逻辑实在太繁琐了，它就是需要几十个步骤来完成，每个步骤还会有若干个分支，而这本身又只是一个很小的功能点（比如读取 DDS 图片文件头），为了代码“优雅”所付出的成本远高于其价值，那这样的重构是否还有必要呢？我个人认为很没有必要，倒不如花点小力气，写些注释，加些换行，把这块又长又复杂的代码弄得阅读起来顺溜些，总比把各个小秘密藏得到处都是好多了。</p>
<p>Related posts:<ul>
<li><a href='http://wutiam.net/2011/08/ugly-code-at-birth-part3/' rel='bookmark' title='代码之初，性本丑？(下)'>代码之初，性本丑？(下)</a></li>
<li><a href='http://wutiam.net/2010/12/ugly-code-at-birth-part1/' rel='bookmark' title='代码之初，性本丑？(上)'>代码之初，性本丑？(上)</a></li>
<li><a href='http://wutiam.net/2009/05/forward-declaration-or-include/' rel='bookmark' title='用 前置声明，还是用 #include？'>用 前置声明，还是用 #include？</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://wutiam.net/2011/01/ugly-code-at-birth-part2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>代码之初，性本丑？(上)</title>
		<link>http://wutiam.net/2010/12/ugly-code-at-birth-part1/</link>
		<comments>http://wutiam.net/2010/12/ugly-code-at-birth-part1/#comments</comments>
		<pubDate>Fri, 17 Dec 2010 00:58:39 +0000</pubDate>
		<dc:creator>islet8</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c++]]></category>

		<guid isPermaLink="false">http://wutiam.net/?p=143</guid>
		<description><![CDATA[我是一个很在意代码质量的人，因为我相信软件开发，细节决定成败（追求细节和拥有宏观视野本身并不矛盾，而且这是另一个话题了）。虽然我并不赞成将团队甚至公司中的每个人的编码风格都硬性规范到某种统一格式，那样不仅会扼杀程序员们的创造力，而且从成本收益来看太不划算了。但是，这并不意味着代码就可以随心所欲地写，所谓“规范”不该是“法律”上的，但一定是“道德”上的：你现在写的代码，要对半年后的你负责，更要对团队里其他同事们负责，甚至可能还有你的客户。而这种责任，不仅仅是代码的功能完整度，更包括可读、健壮和效率。 这几个月有幸参与了我们游戏提升稳定性和优化性能的工作，review了很多代码，这期间时长被各种“富有创造性的”代码雷得外焦里嫩的。碰巧正好看到了《代码之丑》系列文章，感触颇深，有些观点也有些自己的看法，记录下来，与大家探讨。 《代码之丑——开篇》 功能完整的代码，仅仅指的是“能按流程跑起来、不会崩、可以得到正确结果”的代码，这其中的代码质量依然可谓千差万别。在大多数情况下，这些代码可以定义其美丑。不过该文中举的例子可能不够典型，不够丑陋，结果被大家揪住了小尾巴。的确，两种写法都有各自大量的拥趸，也都有各自的理由：比如用 if/else 分别 return 的同学更在意其可 debug 性，而且如果今后要在 if 或 else 的 {} 里加入更多的处理（不仅仅是 return）也很方便；而采用表达式直接 return 的同学更喜欢代码的简洁性。这种时候，你很难让人信服地把这类代码归为丑陋，这只是个人口味不同。 但另一种类似的情况就截然不同了，比如这个函数： inline bool Foo&#40;void&#41; &#123; // 整个函数代码很少，几乎没什么额外功能 ... &#160; if&#40;db.HasNext&#40;&#41;&#41; &#123; return true; &#125; else &#123; return false; &#125; 甚至判断条件简单到只有“db != NULL”之类的语义本身就是纯条件判断的，那这时傻乎乎的用 if/else 就可能贻笑大方了，有人会写出 if (true) return true; else return false; 的代码么？ 《代码之丑（一）——让判断条件做真正的选择》 这篇中提到的问题其实非常常见，因为正常人一般都是先写完了某个函数的调用，然后改吧改吧才发现在不同情况下需要使用不同的参数调这个函数，或者当时写代码时只是想验证这条路是否可行，没太在意避免重复的代码，验证通过后又懒的再去修改已经稳定了的代码。该文中的例子算是客气的，我们有不少代码是在多层 if/else 的每个 [...]
Related posts:<ul>
<li><a href='http://wutiam.net/2010/03/ingenious-usage-of-do-while-0/' rel='bookmark' title='do...while(0) 的妙用'>do...while(0) 的妙用</a></li>
<li><a href='http://wutiam.net/2011/08/ugly-code-at-birth-part3/' rel='bookmark' title='代码之初，性本丑？(下)'>代码之初，性本丑？(下)</a></li>
<li><a href='http://wutiam.net/2011/01/ugly-code-at-birth-part2/' rel='bookmark' title='代码之初，性本丑？(中)'>代码之初，性本丑？(中)</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>我是一个很在意代码质量的人，因为我相信软件开发，细节决定成败（追求细节和拥有宏观视野本身并不矛盾，而且这是另一个话题了）。虽然我并不赞成将团队甚至公司中的每个人的编码风格都硬性规范到某种统一格式，那样不仅会扼杀程序员们的创造力，而且从成本收益来看太不划算了。但是，这并不意味着代码就可以随心所欲地写，所谓“规范”不该是“法律”上的，但一定是“道德”上的：你现在写的代码，要对半年后的你负责，更要对团队里其他同事们负责，甚至可能还有你的客户。而这种责任，不仅仅是代码的<strong>功能完整度</strong>，更包括<strong>可读</strong>、<strong>健壮</strong>和<strong>效率</strong>。</p>
<p>这几个月有幸参与了我们游戏提升稳定性和优化性能的工作，review了很多代码，这期间时长被各种“富有创造性的”代码雷得外焦里嫩的。碰巧正好看到了《<a href="http://www.infoq.com/cn/ugly-code">代码之丑</a>》系列文章，感触颇深，有些观点也有些自己的看法，记录下来，与大家探讨。</p>
<p><span id="more-143"></span><strong>《<a href="http://www.infoq.com/cn/news/2010/11/ugly-code-0">代码之丑——开篇</a>》</strong></p>
<p>功能完整的代码，仅仅指的是“能按流程跑起来、不会崩、可以得到正确结果”的代码，这其中的代码质量依然可谓千差万别。在大多数情况下，这些代码可以定义其美丑。不过该文中举的例子可能不够典型，不够丑陋，结果被大家揪住了小尾巴。的确，两种写法都有各自大量的拥趸，也都有各自的理由：比如用 if/else 分别 return 的同学更在意其可 debug 性，而且如果今后要在 if 或 else 的 {} 里加入更多的处理（不仅仅是 return）也很方便；而采用表达式直接 return 的同学更喜欢代码的简洁性。这种时候，你很难让人信服地把这类代码归为丑陋，这只是个人口味不同。</p>
<p>但另一种类似的情况就截然不同了，比如这个函数：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">bool</span> Foo<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #666666;">// 整个函数代码很少，几乎没什么额外功能</span>
    ...
&nbsp;
    <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>db.<span style="color: #007788;">HasNext</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #008000;">&#123;</span>
       <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>甚至判断条件简单到只有“db != NULL”之类的<strong>语义本身就是纯条件判断</strong>的，那这时傻乎乎的用 if/else 就可能贻笑大方了，有人会写出 if (true) return true; else return false; 的代码么？</p>
<p><strong>《<a href="http://www.infoq.com/cn/news/2010/11/ugly-code-1">代码之丑（一）——让判断条件做真正的选择</a>》</strong></p>
<p>这篇中提到的问题其实非常常见，因为正常人一般都是先写完了某个函数的调用，然后改吧改吧才发现在不同情况下需要使用不同的参数调这个函数，或者当时写代码时只是想验证这条路是否可行，没太在意避免重复的代码，验证通过后又懒的再去修改已经稳定了的代码。该文中的例子算是客气的，我们有不少代码是在多层 if/else 的每个 {} 中都复制了代码，函数调用本身就很长，那么多参数，有差别的只有几个字母，如果哪天这个函数的输入输出改了，想必维护这段代码的同学很难不改出 bug。</p>
<p>程序中最忌讳的陋习之一就是复制代码，这对软件的影响不仅仅是增大程序体积，真正严重的是每当需要修改这段代码，所有它的副本都得记得去改，如果漏掉了一个，哼哼，一个小时内找到问题就算不错了。可又有多少程序员在编码的时候会提醒自己这个问题呢？我想恐怕不超过10%，至少真的能要求自己做到的不会超过这个比例。聪明的懒人，是努力让自己日后更轻松，而不是偷一时之快让自己逐渐进入越忙越乱越乱越忙的恶性循环。</p>
<p>不过，话又要说回来，任何的重构都要有个度，也要有个合适的环境才行。重构的前提是要保持语义清晰，或者是为了语义更清晰而重构，而不能为了重构而重构。对于该文的这个最最简单的例子来说，下面 Shichao Liu 的补充给得很强力：</p>
<blockquote><p>对于仅仅参数不同分支， 也要从分支的业务意义上加以区分：<br />
1.是恰巧逻辑相同，实则业务意义上完全独立的分支。<br />
2.或是业务意义上就应该有完全相同的逻辑操作，而仅是数据有差异。</p>
<p>在需求发生演变时会有所不同。</p>
<p>举个例子，网游， 一次攻击可能是“普通伤害”或者“致命一击”。可能在第一个版本中仅仅是伤害数值有所差异， 而在第二个版本中需要对致命一击后追击一些额外的操作（统计次数，累积点数等等策划能想得到的点子）。</p></blockquote>
<p><strong>《<a href="http://www.infoq.com/cn/news/2010/11/ugly-code-2">代码之丑（二）——长长的条件</a>》</strong></p>
<p>这篇我的认同度就比较低了，的确，该文所述的方法是各大软件公司惯用的技巧（MFC 里就有好多），重构出来的代码<strong>看似</strong>也非常清晰。但，对于第一次阅读或者修改这个代码的人，第一反应估计就是“STR_PREDICATE_ITEM 这个宏都干了啥？靠谱么？后面要不要加分号？BEGIN 和 END 之间加上 {} 会有问题么？太可怕了，又得记住一堆宏定义和用法，而且其实我总是记不起来要去用它们……”这还不是最糟糕的。你不能要求所有的同事都有这种归纳重构的能力，而且就算大家都是重构大拿，在一个项目中把各自写的所有复杂判断条件都这么折腾一趟，要么每个人得给每个判断单独写一套宏（很快就不会有人遵守了，今天还有五个功能等着交付呢），要么有神人来写了套相当泛型的通用宏，哇哦，原本为了可读性而重构出来的代码变得完全没法维护了。最严酷的是，如果条件并不是简单而统一的判断，比如：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>IsOperator<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #000040;">||</span> <span style="color: #008000;">&#40;</span>IsOtherPlayer<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;&amp;</span> GetID<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">100</span><span style="color: #008000;">&#41;</span>
    <span style="color: #000040;">||</span> <span style="color: #008000;">&#40;</span>IsNpc<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;&amp;</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>IsMonster<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">||</span> strResName <span style="color: #000040;">!</span><span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;NNN&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #000040;">||</span> strResName <span style="color: #000080;">==</span> <span style="color: #FF0000;">&quot;RRR&quot;</span>
    <span style="color: #000040;">||</span> strResName.<span style="color: #007788;">Contain</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;XY&quot;</span><span style="color: #008000;">&#41;</span>
    ...<span style="color: #008000;">&#41;</span></pre></div></div>

<p>怎么办？更复杂的多层嵌套呢？应该说出现这类判断的代码，背后的设计一定是有问题的，但如果我们没法解决设计的缺陷，只能努力找一个平衡点，别累死写代码的人，也别搞懵维护代码的人，更别为了追求代码看起来很上流而让所有人都感到反感。</p>
<p>Related posts:<ul>
<li><a href='http://wutiam.net/2010/03/ingenious-usage-of-do-while-0/' rel='bookmark' title='do...while(0) 的妙用'>do...while(0) 的妙用</a></li>
<li><a href='http://wutiam.net/2011/08/ugly-code-at-birth-part3/' rel='bookmark' title='代码之初，性本丑？(下)'>代码之初，性本丑？(下)</a></li>
<li><a href='http://wutiam.net/2011/01/ugly-code-at-birth-part2/' rel='bookmark' title='代码之初，性本丑？(中)'>代码之初，性本丑？(中)</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://wutiam.net/2010/12/ugly-code-at-birth-part1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>#include</title>
		<link>http://wutiam.net/2010/12/include-rules-of-cpp/</link>
		<comments>http://wutiam.net/2010/12/include-rules-of-cpp/#comments</comments>
		<pubDate>Mon, 13 Dec 2010 08:31:51 +0000</pubDate>
		<dc:creator>islet8</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c++]]></category>

		<guid isPermaLink="false">http://wutiam.net/?p=148</guid>
		<description><![CDATA[译自 zeuxcg 的《#include 》（墙外），有删改。请勿转载。 若不听劝告非要转载，请注明出处，谢谢。 我们没法摆脱 C++，至少短期内不太可能。我真希望 C++ 里没有那么多恶心的特性，但目前也没有真正能取代 C++ 的玩意。现代编程语言往往采用大宗编译（bulk compilation）和/或智能链接器，但 C++ 仍然受困于头文件分离的设计思想（当然从另一方面说，C++ 的这种设计也使得其构建过程可以是增量的、高度并行的），使得鱼与熊掌不可兼得。 这种分离头文件并保持代码清晰的策略很显而易见，但我却很纳闷为啥还有那么多人没搞明白到底该怎么使用头文件，希望这篇文章能够进一步理清这团乱麻。本文也适用于 C，但有幸使用其他语言的同学们请绕行。 包含头文件的问题在于预编译器很笨：你的代码告诉它要包含某个文件，那么它就会“递归地”包含整个文件内容；如果你不想包含那个文件却又想用该文件中定义的一个符号呢，那你只有面对编译错误的份了；但你如果把所有头文件都包含进来，哼哼，编译的时候你就去数星星吧。 一般情况下，一个头文件被包含的次数越多（包括递推的包含，比如 A 包含了 B，B 又包含了 C，那么 A 也就包含了 C），那么改动这个头文件就会导致越多的代码文件需要被重编。迭代周期的时间很紧（这是关于时间的另一个话题了），所以我们要尽可能地减少头文件被包含的次数。这就是第一条重要规范：每个文件仅包含其真正需要显式包含的头文件，尽可能地减少包含的数量。遵守这条规范能确保你代码的构建速度不会像拖拉机一样。 现在，假设我们的某个头文件里声明了一个类 A。按照 C++ 的原则，这个类声明在没有声明其他某些符号前不会被编译。例如，A 继承自类 B 并且包含了一个类型是 C 的成员，那么你就需要在声明 A 之前同时将 B 和 C 的声明提供给编译器。有两种方法：在 A 的头文件里包含 B 和 C 的头文件，或者强制 类A 的使用者们每次在使用前都手动地引入 B 和 C 的头文件。问题是有时使用者没法知道这些内在的依赖关系，有时依赖关系又变了，这会让使用者们抓狂的，更崩溃的是，为了包含你写的这么一个头文件，还得莫名其妙地包含一大堆看起来完全无关的头文件。正因如此，所有的头文件都该自给自足——任何人都可以在任一 cpp [...]
Related posts:<ul>
<li><a href='http://wutiam.net/2009/05/forward-declaration-or-include/' rel='bookmark' title='用 前置声明，还是用 #include？'>用 前置声明，还是用 #include？</a></li>
<li><a href='http://wutiam.net/2011/10/game-engine-design-memory-management-framework/' rel='bookmark' title='游戏引擎设计 之 内存管理框架'>游戏引擎设计 之 内存管理框架</a></li>
<li><a href='http://wutiam.net/2010/09/lower_bound-strange-compiling-error-in-ms-stl/' rel='bookmark' title='微软 STL lower_bound() 在 DEBUG 下的诡异编译错误'>微软 STL lower_bound() 在 DEBUG 下的诡异编译错误</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p><em>译自 <a href="http://zeuxcg.org/">zeuxcg</a> 的《<a href="http://zeuxcg.org/2010/11/15/include-rules/">#include</a> 》（墙外），有删改。请勿转载。<br />
若不听劝告非要转载，请注明出处，谢谢。</em></p>
<p>我们没法摆脱 C++，至少短期内不太可能。我真希望 C++ 里没有那么多恶心的特性，但目前也没有真正能取代 C++ 的玩意。现代编程语言往往采用大宗编译（bulk compilation）和/或智能链接器，但 C++ 仍然受困于头文件分离的设计思想（当然从另一方面说，C++ 的这种设计也使得其构建过程可以是增量的、高度并行的），使得鱼与熊掌不可兼得。 这种分离头文件并保持代码清晰的策略很显而易见，但我却很纳闷为啥还有那么多人没搞明白到底该怎么使用头文件，希望这篇文章能够进一步理清这团乱麻。本文也适用于 C，但有幸使用其他语言的同学们请绕行。</p>
<p>包含头文件的问题在于预编译器很笨：你的代码告诉它要包含某个文件，那么它就会“递归地”包含整个文件内容；如果你不想包含那个文件却又想用该文件中定义的一个符号呢，那你只有面对编译错误的份了；但你如果把所有头文件都包含进来，哼哼，编译的时候你就去数星星吧。</p>
<p><span id="more-148"></span>一般情况下，一个头文件被包含的次数越多（包括递推的包含，比如 A 包含了 B，B 又包含了 C，那么 A 也就包含了 C），那么改动这个头文件就会导致越多的代码文件需要被重编。迭代周期的时间很紧（这是关于时间的另一个话题了），所以我们要尽可能地减少头文件被包含的次数。这就是第一条重要规范：<strong>每个文件仅包含其真正需要显式包含的头文件，尽可能地减少包含的数量</strong>。遵守这条规范能确保你代码的构建速度不会像拖拉机一样。</p>
<p>现在，假设我们的某个头文件里声明了一个类 A。按照 C++ 的原则，这个类声明在没有声明其他某些符号前不会被编译。例如，A 继承自类 B 并且包含了一个类型是 C 的成员，那么你就需要在声明 A 之前同时将 B 和 C 的声明提供给编译器。有两种方法：在 A 的头文件里包含 B 和 C 的头文件，或者强制 类A 的使用者们每次在使用前都手动地引入 B 和 C 的头文件。问题是有时使用者没法知道这些内在的依赖关系，有时依赖关系又变了，这会让使用者们抓狂的，更崩溃的是，为了包含你写的这么一个头文件，还得莫名其妙地包含一大堆看起来完全无关的头文件。正因如此，所有的头文件都该自给自足——任何人都可以在任一 cpp 中包含任何一个头文件而不会产生编译错误。这就是第二条重要规范：<strong>每个文件都必须包含所有依赖的头文件</strong>。遵守这条规范能确保程序员们不会被混乱的依赖关系逼疯。</p>
<p>以上这两大规范共同框定了如何正确编写头文件的方法：</p>
<ul>
<li>为每个需要的声明包含相应的头文件到你的头文件里；</li>
<li>但千万不要包含别的头文件了。</li>
</ul>
<p>也就是说，如果能用<a href="http://software.intel.com/zh-cn/blogs/2010/05/04/c-2/">前置声明</a>，千万别把整个头文件都包含进来——尽量使用前置声明。花一些时间和精力去解除头文件依赖关系有时是值得的，例如使用 <a href="http://www.codeproject.com/KB/tips/PIMPL.aspx">PIMPL 模式</a>（这个得视情况而定，并非套上了模式就上流了；不过得避免包含重量级的平台文件，比如 windows.h 或 d3d9.h）（关于怎么给 D3D9 的编译瘦身，作者去年的<a href="http://zeuxcg.org/2009/03/22/miscellanea/">这篇文章</a>最后一段有讲，供参考）。</p>
<p>还有一件事，由于疏忽或者意外，我们可能把同一个头文件包含了两次（例如 A 依赖于 B 和 C，而 B 又依赖于 C，所以 C 的头文件就被 A 包含了两次），所以我们需要一种机制来确保不会出现这种问题。我们得让每个文件都能够检测到多重包含，这里有两个办法：使用 #pragma once 或者使用。#pragma once 是一种非标准的技巧，它明确地告知预处理器“不要重复包含当前这个头文件”。而 header guard （也叫做 #include guard 或 macro guard）则通过预编译器的定义来模拟这样一种行为：</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#ifndef FILE_NAME_H</span>
<span style="color: #339900;">#define FILE_NAME_H</span>
...
<span style="color: #339900;">#endif</span></pre></div></div>

<p>可能很多人不知道这种方法，但 #pragma once 已经被现代编译器广泛支持了。它有两点比 header guard 更好：</p>
<ul>
<li>更快（MSVC 不会第二次读取标记有 #pragma once 的文件，但却会读若干遍用 header guard 的文件）；</li>
<li>更简单（不需要再为每个文件的 header guard 取名了，也就不会再把名字搞混了）。</li>
</ul>
<p>所以，<strong>尽量使用 #pragma once，就算用不了，至少也得使用 header guard</strong>。如果你所使用的编译器不支持 #pragma once（而且你也没法说服开发商添加这个功能），那得<strong>确保你使用了一套能够生成永不重名 header guard 的方法</strong>。例如，把文件名连同路径一起转成以下划线（代表子文件夹）分隔的大写字符串，如 THEGAME_RENDER_LIGHTING_POINTLIGHT_H。<strong>不要</strong>只使用文件名，它可能<strong>不是</strong>唯一的！</p>
<p>如果你使用的是 header guard，理论上你可以在任何地方判断当前是否已经包含了某个头文件。但是，别通过判断是否已包含了某个头文件来改变后续代码的走势！这么干就等于让程序依赖于包含头文件的顺序，不但违反了一般性认知，而且由于没有预编译器的输出而无从 debug。如果你觉得你需要干诸如“如果当前包含了渲染器接口，那么我就该加入光照渲染器类，否则就不该让这堆用不到的代码被加进来”，那你应该把你的头文件分成两个类，第二个文件应该明确地包含渲染器接口，因为就是和它有关嘛。</p>
<p>至少在开发游戏的过程中，。最常见的可能就是断言的宏定义了（由于标准的 assert 实在太烂了，你得定义一套符合你们开发需求的），当然其实还有更多：日志接口、min/max函数、跨平台的定义（“当前系统是高位在前的字节顺序么？”）、内存管理相关的宏定义等等。一般惯例是把这些都放到一个单独的通用头文件里。所以你得控制这个文件的 size（当然，你知道我这里的 size 指的是累计包含进该头文件里的所有头文件的大小），而且你得<strong>确保所有文件都是在第一行先包含了这个头文件</strong>——否则你就有麻烦了（可能你得花上几个小时来查原因）。</p>
<p>呼，我能想到的关于头文件的就是这些了。额，还得再罗嗦几句，关于包含路径的问题。包含头文件时，你得指定是相对于当前文件的路径呢，还是相对于某个 include directories 全局设置项：</p>
<ul>
<li><strong>如果你是在写库代码</strong>，当然我说的是相对较小的库啦（像虚幻引擎这种巨人级的平台直接忽略），应该尽量降低配置门槛，也就是理论上不要强迫使用者把你的库加到 include directories 配置列表里去。对于这类工程，<strong>建议使用相对当前文件的的包含路径</strong>。</li>
<li>其他情况下，包含路径应该便于查找，也就是所有被包含的文件应该在同一个路径下。这时<strong>建议使用相对 include directory 配置项的包含路径</strong>，同时还要确保包含<strong>路径没有二义性</strong>。</li>
<li>不管用哪种包含路径的方式，请<strong>尽力保持项目间的一致性</strong>。理论上讲，每个项目的 include directories 配置都应该是一样的，比如引擎工程的设置应该是游戏工程的严格子集。</li>
</ul>
<p>噢，我是不是没提到良好的头文件依赖关系还能加快工程的链接速度？</p>
<p>Related posts:<ul>
<li><a href='http://wutiam.net/2009/05/forward-declaration-or-include/' rel='bookmark' title='用 前置声明，还是用 #include？'>用 前置声明，还是用 #include？</a></li>
<li><a href='http://wutiam.net/2011/10/game-engine-design-memory-management-framework/' rel='bookmark' title='游戏引擎设计 之 内存管理框架'>游戏引擎设计 之 内存管理框架</a></li>
<li><a href='http://wutiam.net/2010/09/lower_bound-strange-compiling-error-in-ms-stl/' rel='bookmark' title='微软 STL lower_bound() 在 DEBUG 下的诡异编译错误'>微软 STL lower_bound() 在 DEBUG 下的诡异编译错误</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://wutiam.net/2010/12/include-rules-of-cpp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python 入门，就这么简单 程序员版</title>
		<link>http://wutiam.net/2010/11/quick-python-script-explanation-for-programmers/</link>
		<comments>http://wutiam.net/2010/11/quick-python-script-explanation-for-programmers/#comments</comments>
		<pubDate>Mon, 01 Nov 2010 02:30:09 +0000</pubDate>
		<dc:creator>islet8</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://wutiam.net/?p=149</guid>
		<description><![CDATA[No related posts.
No related posts.]]></description>
			<content:encoded><![CDATA[<p><a href="http://i.imgur.com/YQafj.png"><img class="alignnone" title="Quick Python Script Explanation for Programmers" src="http://i.imgur.com/YQafj.png" alt="" width="99%" /></a></p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://wutiam.net/2010/11/quick-python-script-explanation-for-programmers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>微软 STL lower_bound() 在 DEBUG 下的诡异编译错误</title>
		<link>http://wutiam.net/2010/09/lower_bound-strange-compiling-error-in-ms-stl/</link>
		<comments>http://wutiam.net/2010/09/lower_bound-strange-compiling-error-in-ms-stl/#comments</comments>
		<pubDate>Tue, 28 Sep 2010 09:02:14 +0000</pubDate>
		<dc:creator>islet8</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[vs/vc++]]></category>

		<guid isPermaLink="false">http://wutiam.net/?p=136</guid>
		<description><![CDATA[众所周知，在 STL 中，对于有序的 vector 容器，使用 binary_search、lower_bound/upper_bound 等搜索算法要比直接 find 高效得多。但是由于各个 STL 实现版本没有统一的标准，在 DEBUG 环境下各自的校验机制千差万别，这就导致可能出现一些让人郁闷的情况，比如这次的主角，微软的 STL。 现在有一个有序容器 kTasks，比如是 vector 或 deque，容器中保存的是 task 对象，task 对象中有一个 priority 的属性，容器以 task 的 priority 值降序排序。我们需要频繁查询当前该容器中有多少个 task 的 priority 高于一个给定的值，最高效的办法之一是通过 std::lower_bound() 直接拿到区间，再用 std::distance() 直接统计就行了。 1 2 3 4 5 6 7 8 9 10 11 bool PriorityLesser&#40;CTask* pkTask, int nPriority&#41; &#123; return pkTask-&#62;GetPriority&#40;&#41; [...]
Related posts:<ul>
<li><a href='http://wutiam.net/2009/05/ctreectrl-traversal/' rel='bookmark' title='遍历 CTreeCtrl'>遍历 CTreeCtrl</a></li>
<li><a href='http://wutiam.net/2011/10/game-engine-design-memory-management-framework/' rel='bookmark' title='游戏引擎设计 之 内存管理框架'>游戏引擎设计 之 内存管理框架</a></li>
<li><a href='http://wutiam.net/2010/03/ingenious-usage-of-do-while-0/' rel='bookmark' title='do...while(0) 的妙用'>do...while(0) 的妙用</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>众所周知，在 STL 中，对于有序的 vector 容器，使用 binary_search、lower_bound/upper_bound 等搜索算法要比直接 find 高效得多。但是由于各个 STL 实现版本没有统一的标准，在 DEBUG 环境下各自的校验机制千差万别，这就导致可能出现一些让人郁闷的情况，比如这次的主角，微软的 STL。</p>
<p><span id="more-136"></span>现在有一个有序容器 kTasks，比如是 vector 或 deque，容器中保存的是 task 对象，task 对象中有一个 priority 的属性，容器以 task 的 priority 值降序排序。我们需要频繁查询当前该容器中有多少个 task 的 priority 高于一个给定的值，最高效的办法之一是通过 std::lower_bound() 直接拿到区间，再用 std::distance() 直接统计就行了。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">bool</span> PriorityLesser<span style="color: #008000;">&#40;</span>CTask<span style="color: #000040;">*</span> pkTask, <span style="color: #0000ff;">int</span> nPriority<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> pkTask<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>GetPriority<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&gt;=</span> nPriority<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> CountIfPriorityIsGE<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> nPriority<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">return</span> kTasks.<span style="color: #007788;">empty</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> 
        <span style="color: #008080;">?</span> <span style="color: #0000dd;">0</span>
        <span style="color: #008080;">:</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span>std<span style="color: #008080;">::</span><span style="color: #007788;">distance</span><span style="color: #008000;">&#40;</span>kTasks.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, std<span style="color: #008080;">::</span><span style="color: #007788;">lower_bound</span><span style="color: #008000;">&#40;</span>kTasks.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, kTasks.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, nPriority, PriorityLesser<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>杯具就这么来了，由于这里使用的 std::lower_bound() 是带比较器的，在 DEBUG 模式下编译不过（RELEASE 下没问题），错误很莫名其妙，类似这样：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">error C2664: 'bool (CTask *,int)' : cannot convert parameter 2 from 'CTask *' to 'int'
...
see reference to function template instantiation 'bool std::_Debug_lt_pred&lt;_Pr,CTask*,_Ty&gt;(_Pr,_Ty1 &amp;,const _Ty2 &amp;,const wchar_t *,unsigned int)' being compiled</pre></div></div>

<p>这是啥破玩意儿呀？！MSDN 里的例子很简单，也没说有这种情况，难道是微软 STL 的 bug？没看到有人报过啊。只好硬着头皮看 MS STL 天书般的源代码了。</p>
<p>先来看看 lower_bound() 的代码（知道啥是天书了吧）：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">		<span style="color: #666666;">// TEMPLATE FUNCTION lower_bound WITH PRED</span>
<span style="color: #0000ff;">template</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> _FwdIt,
	<span style="color: #0000ff;">class</span> _Ty,
	<span style="color: #0000ff;">class</span> _Diff,
	<span style="color: #0000ff;">class</span> _Pr<span style="color: #000080;">&gt;</span> <span style="color: #0000ff;">inline</span>
	_FwdIt _Lower_bound<span style="color: #008000;">&#40;</span>_FwdIt _First, _FwdIt _Last,
		<span style="color: #0000ff;">const</span> _Ty<span style="color: #000040;">&amp;</span> _Val, _Pr _Pred, _Diff <span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>
	<span style="color: #008000;">&#123;</span>	<span style="color: #666666;">// find first element not before _Val, using _Pred</span>
	_DEBUG_POINTER<span style="color: #008000;">&#40;</span>_Pred<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	_DEBUG_ORDER_SINGLE_PRED<span style="color: #008000;">&#40;</span>_First, _Last, _Pred, <span style="color: #0000ff;">true</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	_Diff _Count <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
	_Distance<span style="color: #008000;">&#40;</span>_First, _Last, _Count<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	<span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #008080;">;</span> <span style="color: #0000dd;">0</span> <span style="color: #000080;">&lt;</span> _Count<span style="color: #008080;">;</span> <span style="color: #008000;">&#41;</span>
		<span style="color: #008000;">&#123;</span>	<span style="color: #666666;">// divide and conquer, find half that contains answer</span>
		_Diff _Count2 <span style="color: #000080;">=</span> _Count <span style="color: #000040;">/</span> <span style="color: #0000dd;">2</span><span style="color: #008080;">;</span>
		_FwdIt _Mid <span style="color: #000080;">=</span> _First<span style="color: #008080;">;</span>
		std<span style="color: #008080;">::</span><span style="color: #007788;">advance</span><span style="color: #008000;">&#40;</span>_Mid, _Count2<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
		_DEBUG_ORDER_SINGLE_PRED<span style="color: #008000;">&#40;</span>_Mid, _Last, _Pred, <span style="color: #0000ff;">false</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
		<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>_DEBUG_LT_PRED<span style="color: #008000;">&#40;</span>_Pred, <span style="color: #000040;">*</span>_Mid, _Val<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
			_First <span style="color: #000080;">=</span> <span style="color: #000040;">++</span>_Mid, _Count <span style="color: #000040;">-</span><span style="color: #000080;">=</span> _Count2 <span style="color: #000040;">+</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
		<span style="color: #0000ff;">else</span>
			_Count <span style="color: #000080;">=</span> _Count2<span style="color: #008080;">;</span>
		<span style="color: #008000;">&#125;</span>
	<span style="color: #0000ff;">return</span> <span style="color: #008000;">&#40;</span>_First<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>先注意第 10 行和第 18 行的这两个 _DEBUG_ORDER_SINGLE_PRED()，再往里跟，这个宏在 DEBUG 模式下实际执行的代码基本就是：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">class</span> _Pr, <span style="color: #0000ff;">class</span> _Ty1, <span style="color: #0000ff;">class</span> _Ty2<span style="color: #000080;">&gt;</span> <span style="color: #0000ff;">inline</span>
	<span style="color: #0000ff;">bool</span> __CLRCALL_OR_CDECL _Debug_lt_pred<span style="color: #008000;">&#40;</span>_Pr _Pred, <span style="color: #0000ff;">const</span> _Ty1<span style="color: #000040;">&amp;</span> _Left, _Ty2<span style="color: #000040;">&amp;</span> _Right,
		<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">wchar_t</span> <span style="color: #000040;">*</span>_Where, <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> _Line<span style="color: #008000;">&#41;</span>
	<span style="color: #008000;">&#123;</span>	<span style="color: #666666;">// test if _Pred(_Left, _Right) and _Pred is strict weak ordering</span>
	<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #000040;">!</span>_Pred<span style="color: #008000;">&#40;</span>_Left, _Right<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
		<span style="color: #0000ff;">return</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">false</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	<span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>_Pred<span style="color: #008000;">&#40;</span>_Right, _Left<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
		_DEBUG_ERROR2<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;invalid operator&lt;&quot;</span>, _Where, _Line<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	<span style="color: #0000ff;">return</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">true</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
	<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>因为这时传入的都是容器的 iterator，所以实际上是在检查当前容器是否真的有序。。。</p>
<p>这还不算完，再看 lower_bound() 第 20 行的 _DEBUG_LT_PRED()，这个宏在 RELEASE 下是直接调用比较器，而在 DEBUG 下，又是去调用了上面那个 _Debug_lt_pred()，但传入的参数是一个迭代器和一个比较值，也就是既要做正常判断，又要检查反向比较时得到的结果是否正好相反。</p>
<p>终于明白了 DEBUG 下 lower_bound() 都干了些啥，那问题就好解决了。我们的比较器只提供了正常的比较操作（左项为迭代器、右项为比较值），还缺少用于检查容器是否有序的比较器（左右项都为迭代器）和用于检查反向比较的比较器（左项为比较值、右项为迭代器），这么一来，比较器就不能再使用普通函数了，必须以仿函数类的形式来提供所需的三种功能：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">struct</span> PriorityLesser
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">bool</span> operator<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span>CTask<span style="color: #000040;">*</span> pkTask, <span style="color: #0000ff;">int</span> nPriority<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">return</span> pkTask<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>GetPriority<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&gt;=</span> nPriority<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #339900;">#ifdef _DEBUG</span>
    <span style="color: #0000ff;">bool</span> operator<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> nPriority, CTask<span style="color: #000040;">*</span> pkTask<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">return</span> pkTask<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>GetPriority<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&gt;=</span> nPriority<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">bool</span> operator<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span>CTask<span style="color: #000040;">*</span> pkTask1, CTask<span style="color: #000040;">*</span> pkTask2<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">return</span> pkTask1<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>GetPriority<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&gt;</span> pkTask2<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>GetPriority<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #339900;">#endif // _DEBUG</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span> CountIfPriorityIsGE<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> nPriority<span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>kTasks.<span style="color: #007788;">empty</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    OperationQueue<span style="color: #008080;">::</span><span style="color: #007788;">iterator</span> itr <span style="color: #000080;">=</span> std<span style="color: #008080;">::</span><span style="color: #007788;">lower_bound</span><span style="color: #008000;">&#40;</span>kTasks.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, kTasks.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, nPriority, PriorityLesser<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    OperationQueue<span style="color: #008080;">::</span><span style="color: #007788;">difference_type</span> diff <span style="color: #000080;">=</span> std<span style="color: #008080;">::</span><span style="color: #007788;">distance</span><span style="color: #008000;">&#40;</span>kTasks.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, itr<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span>diff<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>呼～</p>
<p>Related posts:<ul>
<li><a href='http://wutiam.net/2009/05/ctreectrl-traversal/' rel='bookmark' title='遍历 CTreeCtrl'>遍历 CTreeCtrl</a></li>
<li><a href='http://wutiam.net/2011/10/game-engine-design-memory-management-framework/' rel='bookmark' title='游戏引擎设计 之 内存管理框架'>游戏引擎设计 之 内存管理框架</a></li>
<li><a href='http://wutiam.net/2010/03/ingenious-usage-of-do-while-0/' rel='bookmark' title='do...while(0) 的妙用'>do...while(0) 的妙用</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://wutiam.net/2010/09/lower_bound-strange-compiling-error-in-ms-stl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Process Explorer，程序员的任务管理器</title>
		<link>http://wutiam.net/2010/09/process-explorer-for-programmers-as-the-substitution-of-win-task-manager/</link>
		<comments>http://wutiam.net/2010/09/process-explorer-for-programmers-as-the-substitution-of-win-task-manager/#comments</comments>
		<pubDate>Tue, 28 Sep 2010 05:20:05 +0000</pubDate>
		<dc:creator>islet8</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://wutiam.net/?p=137</guid>
		<description><![CDATA[今天在一位曾经的专业是经济管理学的编程大拿那儿看到了 PE 这个小工具的推荐，下来试用了下果然超级强大，已然让我放弃 Windows 自带任务管理器。PE 的基本功能见下图，一目了然，不仅能以层级关系列出所有进程，其 CPU 占用、内存占用等数值统计和 CPU 历史占用图也更符合程序员的需求。 PE 还可以显示每个进程当前打开的所有文件、注册表项和其他信息，这对于检查程序是否有文件泄漏（fopen 了忘了 fclose 等情况）相当有帮助。而在 DLL 模式下，PE 还能检查 DLL 版本问题、路径及句柄泄漏之类的问题，怎一个爽字了得！ 在系统信息界面，除了把物理内存占用和总内存分开显示外，还增加了 I/O 历史，还在 XP 下奋斗的同学们不用再哭泣了。 如果你是程序员，那还在等什么呢？（ SysInternals 中包含了大量有用的小工具，PE 只是其中的一个） P.S. 64位系统的同学要替换掉系统的任务管理器，参见这里。 Related posts: 禁止 Windows Update 安装更新后自动重启 被病毒修改并锁定了 DNS WMP 11 不支持包含 UTF-8 编码 ID3v2 的 MP3 文件
Related posts:<ul>
<li><a href='http://wutiam.net/2009/05/disable-automatic-restart-after-windows-update/' rel='bookmark' title='禁止 Windows Update 安装更新后自动重启'>禁止 Windows Update 安装更新后自动重启</a></li>
<li><a href='http://wutiam.net/2008/12/virus-modified-and-locked-my-dns/' rel='bookmark' title='被病毒修改并锁定了 DNS'>被病毒修改并锁定了 DNS</a></li>
<li><a href='http://wutiam.net/2008/11/wmp11-does-not-support-mp3-with-id3v2-in-utf8/' rel='bookmark' title='WMP 11 不支持包含 UTF-8 编码 ID3v2 的 MP3 文件'>WMP 11 不支持包含 UTF-8 编码 ID3v2 的 MP3 文件</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>今天在一位曾经的专业是经济管理学的编程大拿那儿看到了 <a title="Process Explorer" href="http://technet.microsoft.com/pl-pl/sysinternals/bb896653%28en-us%29.aspx">PE</a> 这个小工具的<a title="Debugging file leaks – the easy way" href="http://msinilo.pl/blog/?p=54">推荐</a>，下来试用了下果然超级强大，已然让我放弃 Windows 自带任务管理器。PE 的基本功能见下图，一目了然，不仅能以层级关系列出所有进程，其 CPU 占用、内存占用等数值统计和 CPU 历史占用图也更符合程序员的需求。</p>
<p><a href="http://picasaweb.google.com/lh/photo/d2Nxz_4-tjzhqj0eBz7vCitDwvBaRwcziDW2XJv0KqA?feat=embedwebsite"><img src="http://lh6.ggpht.com/_p7iGbn8Pr24/TKFy3ObI60I/AAAAAAAACDU/BVIuGJfPNYE/s400/PE1.PNG" alt="" /></a></p>
<p><span id="more-137"></span>PE 还可以显示每个进程当前打开的所有文件、注册表项和其他信息，这对于检查程序是否有文件泄漏（fopen 了忘了 fclose 等情况）相当有帮助。而在 DLL 模式下，PE 还能检查 DLL 版本问题、路径及句柄泄漏之类的问题，怎一个爽字了得！</p>
<p><a href="http://picasaweb.google.com/lh/photo/EdBr_uQ6JwtAbXG6TLJRyitDwvBaRwcziDW2XJv0KqA?feat=embedwebsite"><img src="http://lh4.ggpht.com/_p7iGbn8Pr24/TKFy3liUjUI/AAAAAAAACDY/AytdV9K2L08/s400/PE2.PNG" alt="" /></a></p>
<p>在系统信息界面，除了把物理内存占用和总内存分开显示外，还增加了 I/O 历史，还在 XP 下奋斗的同学们不用再哭泣了。</p>
<p>如果你是程序员，那还在等什么呢？（ <a title="Sysinternals Utilities Index" href="http://technet.microsoft.com/pl-pl/sysinternals/bb545027%28en-us%29.aspx">SysInternals</a> 中包含了大量有用的小工具，PE 只是其中的一个）</p>
<p>P.S. 64位系统的同学要替换掉系统的任务管理器，参见<a title="Process Explorer &amp; 64-bit OS" href="http://msinilo.pl/blog/?p=628">这里</a>。</p>
<p>Related posts:<ul>
<li><a href='http://wutiam.net/2009/05/disable-automatic-restart-after-windows-update/' rel='bookmark' title='禁止 Windows Update 安装更新后自动重启'>禁止 Windows Update 安装更新后自动重启</a></li>
<li><a href='http://wutiam.net/2008/12/virus-modified-and-locked-my-dns/' rel='bookmark' title='被病毒修改并锁定了 DNS'>被病毒修改并锁定了 DNS</a></li>
<li><a href='http://wutiam.net/2008/11/wmp11-does-not-support-mp3-with-id3v2-in-utf8/' rel='bookmark' title='WMP 11 不支持包含 UTF-8 编码 ID3v2 的 MP3 文件'>WMP 11 不支持包含 UTF-8 编码 ID3v2 的 MP3 文件</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://wutiam.net/2010/09/process-explorer-for-programmers-as-the-substitution-of-win-task-manager/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>避免在 C++ 类结构中出现私有虚成员函数</title>
		<link>http://wutiam.net/2010/07/avoid-private-virtual-member-function-in-cpp-class/</link>
		<comments>http://wutiam.net/2010/07/avoid-private-virtual-member-function-in-cpp-class/#comments</comments>
		<pubDate>Tue, 27 Jul 2010 12:34:44 +0000</pubDate>
		<dc:creator>islet8</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[c++]]></category>

		<guid isPermaLink="false">http://wutiam.net/?p=134</guid>
		<description><![CDATA[最近在重构 C++ 代码时突然想起，如果一个基类的虚成员函数被设为 private，有没有意义？又是否合理？ 当然，有其一定的意义，那就是不希望子类在其他地方调用父类的这个函数，包括在子类的实现中；如果需要这个功能，应该使用其 public 的接口去使用该功能。而子类可以提供自己的实现，以提供多态。但是，如果子类觉得需要，还可以把这个 private 的虚成员函数重定义成 protected（虽然这会让人迷惑），从而使子类的子类们调用它。 有同学可能会问，如果是一个 private 的纯虚成员函数（语法上当然合理），那语义合理么？嗯，我觉得这的确是个问题——也许是为了告诉写子类的其他同学，这个虚函数，我不希望你们在除了基类已有的接口里调用之外还来用——仅仅是一个道德约束？！ 嗯，C++ 就是灵活得过头了，什么都让程序员自己去把控，可是别忘了，“太多的选择比没有选择糟糕得多”。所以，我决定，为了自己也为了别人不犯迷糊，避免使用 private 的虚函数，private 的成员函数仅包含当前类自己使用的函数。 BTW，类的成员变量正好相反，能设为 private 的尽量不要 protected 更不要public，否则后期维护，嗯嗯，就太痛苦了。 Related posts: 游戏引擎设计 之 内存管理框架 用 前置声明，还是用 #include？ #ifdef 中的逻辑与或操作
Related posts:<ul>
<li><a href='http://wutiam.net/2011/10/game-engine-design-memory-management-framework/' rel='bookmark' title='游戏引擎设计 之 内存管理框架'>游戏引擎设计 之 内存管理框架</a></li>
<li><a href='http://wutiam.net/2009/05/forward-declaration-or-include/' rel='bookmark' title='用 前置声明，还是用 #include？'>用 前置声明，还是用 #include？</a></li>
<li><a href='http://wutiam.net/2009/08/logical-and-or-operation-in-ifdef/' rel='bookmark' title='#ifdef 中的逻辑与或操作'>#ifdef 中的逻辑与或操作</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>最近在重构 C++ 代码时突然想起，如果一个基类的虚成员函数被设为 private，有没有意义？又是否合理？</p>
<p>当然，有其一定的意义，那就是不希望子类在其他地方调用父类的这个函数，包括在子类的实现中；如果需要这个功能，应该使用其 public 的接口去使用该功能。而子类可以提供自己的实现，以提供多态。但是，如果子类觉得需要，还可以把这个 private 的虚成员函数重定义成 protected（虽然这会让人迷惑），从而使子类的子类们调用它。</p>
<p>有同学可能会问，如果是一个 private 的纯虚成员函数（语法上当然合理），那语义合理么？嗯，我觉得这的确是个问题——也许是为了告诉写子类的其他同学，这个虚函数，我不希望你们在除了基类已有的接口里调用之外还来用——仅仅是一个道德约束？！</p>
<p>嗯，C++ 就是灵活得过头了，什么都让程序员自己去把控，可是别忘了，“太多的选择比没有选择糟糕得多”。所以，我决定，为了自己也为了别人不犯迷糊，避免使用 private 的虚函数，private 的成员函数仅包含当前类自己使用的函数。</p>
<p>BTW，类的成员变量正好相反，能设为 private 的尽量不要 protected 更不要public，否则后期维护，嗯嗯，就太痛苦了。</p>
<p>Related posts:<ul>
<li><a href='http://wutiam.net/2011/10/game-engine-design-memory-management-framework/' rel='bookmark' title='游戏引擎设计 之 内存管理框架'>游戏引擎设计 之 内存管理框架</a></li>
<li><a href='http://wutiam.net/2009/05/forward-declaration-or-include/' rel='bookmark' title='用 前置声明，还是用 #include？'>用 前置声明，还是用 #include？</a></li>
<li><a href='http://wutiam.net/2009/08/logical-and-or-operation-in-ifdef/' rel='bookmark' title='#ifdef 中的逻辑与或操作'>#ifdef 中的逻辑与或操作</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://wutiam.net/2010/07/avoid-private-virtual-member-function-in-cpp-class/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>VS2010 中的 C++ 0x 新特性：Lambdas、auto 和 static_assert</title>
		<link>http://wutiam.net/2010/06/lambdas-auto-and-static-assert-c-0x-features-in-vc10/</link>
		<comments>http://wutiam.net/2010/06/lambdas-auto-and-static-assert-c-0x-features-in-vc10/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 09:59:39 +0000</pubDate>
		<dc:creator>islet8</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[vs/vc++]]></category>

		<guid isPermaLink="false">http://wutiam.net/?p=132</guid>
		<description><![CDATA[转载自痴痴笑笑的博客，略有删改。 尽管 C++ 社区对 C++ 0x 很是追捧，但是各厂商对于新标准的支持并不热乎。盼星星盼月亮，微软作为 Windows 平台上最强势的 C++ 编译器厂商也终于在 Visual Studio 2010 中开始支持 C++ 0x 的特性。 Visual Studio 2010 中的 Visual C++ 编译器，即 VC10, 包含了 4 个 C++ 0x 的语言特性：lambda 表达式，自动类型推演（auto 关键字），静态断言（static_assert）和右值引用（rvalue reference）。 Lambda 表达式 使用过函数式编程语言（如 LISP、 F#）或一些动态语言（如 Python、Javascript）的大侠对于 lambda 表达式一定不会陌生。在 C++ 0x 中，引入了 lambda 表达式来定义无名仿函数。下面是一个 lambda 表达式的简单例子： 1 2 3 4 5 [...]
Related posts:<ul>
<li><a href='http://wutiam.net/2009/06/uninstalling-visual-studio-2008-may-fail-to-load-setup-components/' rel='bookmark' title='Visual Studio 2008 无法进入修复/卸载界面的解决办法'>Visual Studio 2008 无法进入修复/卸载界面的解决办法</a></li>
<li><a href='http://wutiam.net/2009/04/some-vs2005-and-vs2008-wizards-pop-up-script-error/' rel='bookmark' title='IE8 引发 VS 2005/2008 向导出错的解决方案'>IE8 引发 VS 2005/2008 向导出错的解决方案</a></li>
<li><a href='http://wutiam.net/2009/05/msg-response-for-dynamic-created-ctreectrl-instance/' rel='bookmark' title='动态创建的 CTreeCtrl 实例的消息响应'>动态创建的 CTreeCtrl 实例的消息响应</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>转载自<a href="http://www.cnblogs.com/brucejia/" target="_blank">痴痴笑笑的博客</a>，略有删改。</p>
<p>尽管 C++ 社区对 C++ 0x 很是追捧，但是各厂商对于新标准的支持并不热乎。盼星星盼月亮，微软作为 Windows 平台上最强势的 C++ 编译器厂商也终于在 Visual Studio 2010 中开始支持 C++ 0x 的特性。</p>
<p>Visual Studio 2010 中的 Visual C++ 编译器，即 VC10, 包含了 4 个 C++ 0x 的语言特性：lambda 表达式，自动类型推演（auto 关键字），静态断言（static_assert）和右值引用（rvalue reference）。<br />
<span id="more-132"></span></p>
<h3>Lambda 表达式</h3>
<p>使用过函数式编程语言（如 LISP、 F#）或一些动态语言（如 Python、Javascript）的大侠对于 lambda 表达式一定不会陌生。在 C++ 0x 中，引入了 lambda 表达式来定义无名仿函数。下面是一个 lambda 表达式的简单例子：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;algorithm&gt;</span>
<span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #339900;">#include &lt;ostream&gt;</span>
<span style="color: #339900;">#include &lt;vector&gt;</span>
&nbsp;
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>运行结果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">0 1 2 3 4 5 6 7 8 9</pre></div></div>

<p>for_each 一行中，中括号 [] 称为 lambda introducer，它告诉编译器接下来的是一个 lambda 表达式；接下来 (int n) 是 lambda 表达式的参数声明；最后大括号里边就是“函数体”了。</p>
<p>注意这里因为 lambda 表达式生成的是 functor，所以“函数体”实际上是指这个 functor 的 operator() 的调用部分。你也许会问：那么返回值呢？缺省情况下 lambda 表达式生成的 functor 调用返回类型为 void。</p>
<p>为了方便，以下会用“lambda 返回 void”的简短表述来代替冗长啰嗦的表述—— lambda 表达式生成一个 functor 类型，这个 functor 类型的函数调用操作符（operator()），返回的类型是 void。<br />
请大家一定记住：lambda 表达式生成了类型，并构造该类型的实例。</p>
<p>下面的例子中 lambda 表达式的“函数体”包含多条语句：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;algorithm&gt;</span>
<span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #339900;">#include &lt;ostream&gt;</span>
<span style="color: #339900;">#include &lt;vector&gt;</span>
&nbsp;
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n<span style="color: #008080;">;</span>
&nbsp;
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>n <span style="color: #000040;">%</span> <span style="color: #0000dd;">2</span> <span style="color: #000080;">==</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; even &quot;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #008000;">&#123;</span>
            <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; odd &quot;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>上文提到了 lambda 表达式缺省情况下返回 void，那么如果需要返回其他类型呢？答案是：lambda 表达式的“函数体”中如果有一个 return 的表达式，例如 { return expression; }，那么编译器将自动推演 expression 的类型作为返回类型。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;algorithm&gt;</span>
<span style="color: #339900;">#include &lt;deque&gt;</span>
<span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #339900;">#include &lt;iterator&gt;</span>
<span style="color: #339900;">#include &lt;ostream&gt;</span>
<span style="color: #339900;">#include &lt;vector&gt;</span>
&nbsp;
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    deque<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> d<span style="color: #008080;">;</span>
&nbsp;
    transform<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, front_inserter<span style="color: #008000;">&#40;</span>d<span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000ff;">return</span> n <span style="color: #000040;">*</span> n <span style="color: #000040;">*</span> n<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    for_each<span style="color: #008000;">&#40;</span>d.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, d.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>上例中返回值 n * n * n 很简单，类型推演是显而易见的。但是如果 lambda 表达式中有非常复杂的表达式时，编译器可能无法推演出其类型，或者是推演出现二义性，这时候你可以显式地指明返回值类型。如下所示：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;">transform<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, front_inserter<span style="color: #008000;">&#40;</span>d<span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span> <span style="color: #0000ff;">double</span> <span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>n <span style="color: #000040;">%</span> <span style="color: #0000dd;">2</span> <span style="color: #000080;">==</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">return</span> n <span style="color: #000040;">*</span> n <span style="color: #000040;">*</span> n<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">return</span> n <span style="color: #000040;">/</span> <span style="color:#800080;">2.0</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>“-> double”显式地指明了 lambda 表达式的返回类型是 double。</p>
<p>以上例子中的 lambda 都是无状态的，不包含任何数据成员。很多时候我们需要 lambda 包含数据成员以保存状态，这一点可以通过“捕获”局部变量来实现。</p>
<p>Lambda 表达式的导入符（lambda introducer）是空的，也就是“[]”，表明该 lambda 是一个无状态的。但是在 lambda导入符中可以指定一个“捕获列表”，下面的代码中的 lambda 使用了局部变量 x 和 y，将值介于 x 和 y 之间的元素从集合中删除：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">int</span> x <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> y <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;Input: &quot;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cin</span> <span style="color: #000080;">&gt;&gt;</span> x <span style="color: #000080;">&gt;&gt;</span> y<span style="color: #008080;">;</span>
    v.<span style="color: #007788;">erase</span><span style="color: #008000;">&#40;</span>remove_if<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span>x, y<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000ff;">return</span> x <span style="color: #000080;">&lt;</span> n <span style="color: #000040;">&amp;&amp;</span> n <span style="color: #000080;">&lt;</span> y<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>运行结果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">Input: 4 7
0 1 2 3 4 7 8 9</pre></div></div>

<p>上面代码中很重要的一点信息是：lambda 中捕获的局部变量是以“传值”的方式传给匿名函数对象的。在匿名函数对象中，保存有“捕获列表”中局部变量的拷贝。这一点使得匿名函数对象的生命周期能够长于 main 中的 x、y 局部变量。然而这样的传值方式带来几个限制：</p>
<ol>
<li>lambda中的这两个拷贝并不能被改变，因为缺省情况下函数对象的 operator() 是const</li>
<li>有的对象的拷贝操作开销很大或者不可能（例如如果上面代码中的 x、y 是数据库链接或者某个 singleton）</li>
<li>即使在lambda内部修改了 m_a、m_b 也不能够影响外边main函数中的 x 和 y</li>
</ol>
<p>既然有了“传值”，你一定猜到了还会有“传引用”。Bingo! 你是对的。</p>
<p>在讨论“传引用”之前，我们先来看看另一个比较有用的东西。假设你有一大堆的局部变量需要被 lambda 使用，那么你的“捕获列表”将会写的很长，这肯定不是件愉快的事情。</p>
<p>好在 C++ 委员会的老头们也想到了，C++ 0x 中提供了一个省心的东西：如果捕获列表写成 [=]，表示 lambda 将捕获所有的局部变量，当然也是传值方式。这种方式姑且被称为“缺省捕获”：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">int</span> x <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> y <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;Input: &quot;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cin</span> <span style="color: #000080;">&gt;&gt;</span> x <span style="color: #000080;">&gt;&gt;</span> y<span style="color: #008080;">;</span> <span style="color: #666666;">// EVIL!</span>
    v.<span style="color: #007788;">erase</span><span style="color: #008000;">&#40;</span>remove_if<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #000080;">=</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000ff;">return</span> x <span style="color: #000080;">&lt;</span> n <span style="color: #000040;">&amp;&amp;</span> n <span style="color: #000080;">&lt;</span> y<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>当编译器在 lambda 的作用范围内看到局部变量 x、y 时，它会以传值的方式从 main 函数中将它们捕获。</p>
<p>下面我们来看如何突破前面提到的 3 点限制。</p>
<p>第 1 点，修改 lambda 表达式中的局部变量拷贝（e.g. m_a, m_b）。缺省情况下，lambda 的 operator() 是 const 修饰的，但是你可以使用 mutable 关键字改变这一点：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">int</span> x <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> y <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
&nbsp;
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #000080;">=</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #000040;">&amp;</span> r<span style="color: #008000;">&#41;</span> mutable <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> old <span style="color: #000080;">=</span> r<span style="color: #008080;">;</span>
        r <span style="color: #000040;">*</span><span style="color: #000080;">=</span> x <span style="color: #000040;">*</span> y<span style="color: #008080;">;</span>
        x <span style="color: #000080;">=</span> y<span style="color: #008080;">;</span>
        y <span style="color: #000080;">=</span> old<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> x <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;, &quot;</span> <span style="color: #000080;">&lt;&lt;</span> y <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>运行结果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">0 0 0 6 24 60 120 210 336 504
1, 1</pre></div></div>

<p>这里我们解决了第 1 个限制，但是却产生了一个新的限制：</p>
<ol start=4>
<li>lambda 中对捕获变量的修改并不会影响到 main 函数中的局部变量，因为 lambda 捕获局部变量使用的是传值方式</li>
</ol>
<p>下面该“传引用”的方式登场了，它能够有效地解决2，3，4三个限制。传引用的语法为： lambda-introducer [&amp;x, &amp;y]，这里的捕获列表应该理解为：X&amp; x, Y&amp; y，因为我们实际上是取的 x、y 的引用而不是地址。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
&nbsp;
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">int</span> x <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> y <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
&nbsp;
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #000040;">&amp;</span>x, <span style="color: #000040;">&amp;</span>y<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #000040;">&amp;</span> r<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> old <span style="color: #000080;">=</span> r<span style="color: #008080;">;</span>
        r <span style="color: #000040;">*</span><span style="color: #000080;">=</span> x <span style="color: #000040;">*</span> y<span style="color: #008080;">;</span>
        x <span style="color: #000080;">=</span> y<span style="color: #008080;">;</span>
        y <span style="color: #000080;">=</span> old<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> x <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;, &quot;</span> <span style="color: #000080;">&lt;&lt;</span> y <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>运行结果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">0 0 0 6 24 60 120 210 336 504
8, 9</pre></div></div>

<p>注意：当你使用 lambda 时，VC10 编译器会为 lambda 的定义部分自动禁用 C4512 警告。</p>
<p>当以传引用方式捕获局部变量时，lambda 的函数对象在自己内部以引用方式保存 main 函数中的局部变量。当然因为使用的是局部对象的引用，使用lambda表达式时一定要注意不能够超出局部变量的生命周期。</p>
<p>和上文提高的[=]类似，我们可以用[&#038;]来以“传引用”的方式捕获所有的局部变量。</p>
<p>到目前为止，局部变量的捕获方式要么是“值语义”要么是“引用语义”，那么可以混合这两种方式吗？可以！例如：[a, b, c, &amp;d, e, &amp;f, g]，其中变量 d 和 f 是按引用语义捕获，而 a、b、c、e 和 g 是按值语义捕获。</p>
<p>另外很有用的一点是：你可以指定一个缺省捕获，然后重载某些局部变量的捕获方式。下边例子中[=, &amp;sum, &amp;product] 告诉编译器用值语义方式捕获所有的局部变量，但是有两个例外 - sum和product是按引用语义来捕获。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
&nbsp;
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">int</span> sum <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> product <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> x <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> y <span style="color: #000080;">=</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span>
&nbsp;
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #000080;">=</span>, <span style="color: #000040;">&amp;</span>sum, <span style="color: #000040;">&amp;</span>product<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #000040;">&amp;</span> r<span style="color: #008000;">&#41;</span> mutable <span style="color: #008000;">&#123;</span>
        sum <span style="color: #000040;">+</span><span style="color: #000080;">=</span> r<span style="color: #008080;">;</span>
&nbsp;
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>r <span style="color: #000040;">!</span><span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            product <span style="color: #000040;">*</span><span style="color: #000080;">=</span> r<span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
&nbsp;
        <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> old <span style="color: #000080;">=</span> r<span style="color: #008080;">;</span>
        r <span style="color: #000040;">*</span><span style="color: #000080;">=</span> x <span style="color: #000040;">*</span> y<span style="color: #008080;">;</span>
        x <span style="color: #000080;">=</span> y<span style="color: #008080;">;</span>
        y <span style="color: #000080;">=</span> old<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;sum: &quot;</span> <span style="color: #000080;">&lt;&lt;</span> sum <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;, product: &quot;</span> <span style="color: #000080;">&lt;&lt;</span> product <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;x: &quot;</span> <span style="color: #000080;">&lt;&lt;</span> x <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;, y: &quot;</span> <span style="color: #000080;">&lt;&lt;</span> y <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>运行结果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">0 0 0 6 24 60 120 210 336 504
sum: 45, product: 362880
x: 1, y: 1</pre></div></div>

<p>再来看看下边的代码，在lambda中使用类成员变量：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">class</span> Kitty <span style="color: #008000;">&#123;</span>
&nbsp;
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">explicit</span> Kitty<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> toys<span style="color: #008000;">&#41;</span> <span style="color: #008080;">:</span> m_toys<span style="color: #008000;">&#40;</span>toys<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">void</span> meow<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #000040;">&amp;</span> v<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> <span style="color: #008000;">&#123;</span>
        for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span>m_toys<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;If you gave me &quot;</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; toys, I would have &quot;</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000040;">+</span> m_toys <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; toys total.&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">int</span> m_toys<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">3</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    Kitty k<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">5</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    k.<span style="color: #007788;">meow</span><span style="color: #008000;">&#40;</span>v<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>不幸的是，编译这段代码将产生这样的错误：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">error C3480: 'Kitty::m_toys': a lambda capture variable must be from an enclosing function scope</pre></div></div>

<p>为什么呢？lambda表达式能够让你不活局部变量，但是类的数据成员并不是局部变量。解决方案呢？别着急。lambda 为捕获类的数据成员大开方便之门，你可以捕获this指针。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">class</span> Kitty <span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">explicit</span> Kitty<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> toys<span style="color: #008000;">&#41;</span> <span style="color: #008080;">:</span> m_toys<span style="color: #008000;">&#40;</span>toys<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">void</span> meow<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #000040;">&amp;</span> v<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> <span style="color: #008000;">&#123;</span>
        for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;If you gave me &quot;</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; toys, I would have &quot;</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000040;">+</span> m_toys <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; toys total.&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">int</span> m_toys<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">3</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    Kitty k<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">5</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    k.<span style="color: #007788;">meow</span><span style="color: #008000;">&#40;</span>v<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>运行结果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">If you gave me 0 toys, I would have 5 toys total.
If you gave me 1 toys, I would have 6 toys total.
If you gave me 2 toys, I would have 7 toys total.</pre></div></div>

<p>当 lambda 表达式捕获“this”时，编译器看到 m_toys 后会在 this 所指向对象的范围内进行名字查找，m_toys 被隐式地推演为 this-&gt;m_toys。当然你也可以让编译器省省力气，显式地在捕获列表中使用 this-&gt;m_toys。另外，lambda 比较智能，你也可以隐式地捕获 this 指针，如下所示：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">class</span> Kitty <span style="color: #008000;">&#123;</span>
&nbsp;
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">explicit</span> Kitty<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> toys<span style="color: #008000;">&#41;</span> <span style="color: #008080;">:</span> m_toys<span style="color: #008000;">&#40;</span>toys<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">void</span> meow<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #000040;">&amp;</span> v<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> <span style="color: #008000;">&#123;</span>
        for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #000080;">=</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;If you gave me &quot;</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; toys, I would have &quot;</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000040;">+</span> m_toys <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; toys total.&quot;</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">int</span> m_toys<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">3</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    Kitty k<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">5</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    k.<span style="color: #007788;">meow</span><span style="color: #008000;">&#40;</span>v<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>运行结果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">If you gave me 0 toys, I would have 5 toys total.
If you gave me 1 toys, I would have 6 toys total.
If you gave me 2 toys, I would have 7 toys total.</pre></div></div>

<p>注意你也可以在上面代码中用 [&amp;]，但是结果是一样的——this 指针永远是按值语义被传递(捕获)的。你也不能够使用 [&amp;this]，呵呵。</p>
<p>如果你的 lambda 表达式是没有参数的，那么 lambda 表达式的导入符后边的括号()也可以省掉。例如：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
    generate_n<span style="color: #008000;">&#40;</span>back_inserter<span style="color: #008000;">&#40;</span>v<span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">10</span>, <span style="color: #008000;">&#91;</span><span style="color: #000040;">&amp;</span><span style="color: #008000;">&#93;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000ff;">return</span> i<span style="color: #000040;">++</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;i: &quot;</span> <span style="color: #000080;">&lt;&lt;</span> i <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>上边是 [&amp;]() { return i++; }的简写形式，个人认为省掉括号并不是什么好的 coding style。如果你需要用到mutable或者指定lambda的返回类型，空的括号就不能够省略了。</p>
<p>最后，既然 lambda 表达式生成是普通的函数对象，所以函数对象支持的用法 lambda 都支持。例如和 tr1 的 function 一起使用，看看下边的代码，是不是很酷？</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">::</span><span style="color: #007788;">tr1</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">void</span> meow<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span><span style="color: #000040;">&amp;</span> v, <span style="color: #0000ff;">const</span> function<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">void</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span><span style="color: #000080;">&gt;</span><span style="color: #000040;">&amp;</span> f<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    for_each<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, f<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> v<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">10</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        v.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    meow<span style="color: #008000;">&#40;</span>v, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    meow<span style="color: #008000;">&#40;</span>v, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000040;">*</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    function<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">void</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span><span style="color: #000080;">&gt;</span> g <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> n <span style="color: #000040;">*</span> n <span style="color: #000040;">*</span> n <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
    meow<span style="color: #008000;">&#40;</span>v, g<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>运行结果：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">0 1 2 3 4 5 6 7 8 9
0 1 4 9 16 25 36 49 64 81
0 1 8 27 64 125 216 343 512 729</pre></div></div>

<h3>auto 关键字</h3>
<p>auto 这个关键字来自 C++ 98 标准。在 C++ 98 中它没有什么作用，C++ 0x 中“借用”它来作为自动类型推演(automatic type deduction)。当 auto 出现在声明中时，它表示“请用初始化我的表达式类型作为我的类型”，例如下面代码：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #339900;">#include &lt;map&gt;</span>
<span style="color: #339900;">#include &lt;ostream&gt;</span>
<span style="color: #339900;">#include &lt;regex&gt;</span>
<span style="color: #339900;">#include &lt;string&gt;</span>
&nbsp;
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">::</span><span style="color: #007788;">tr1</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    map<span style="color: #000080;">&lt;</span>string, string<span style="color: #000080;">&gt;</span> m<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">const</span> regex r<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;(<span style="color: #000099; font-weight: bold;">\\</span>w+) (<span style="color: #000099; font-weight: bold;">\\</span>w+)&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span>string s<span style="color: #008080;">;</span> getline<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">cin</span>, s<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        smatch results<span style="color: #008080;">;</span>
&nbsp;
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>regex_match<span style="color: #008000;">&#40;</span>s, results, r<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            m<span style="color: #008000;">&#91;</span>results<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> results<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">auto</span> i <span style="color: #000080;">=</span> m.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> i <span style="color: #000040;">!</span><span style="color: #000080;">=</span> m.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> i<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>second <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; are &quot;</span> <span style="color: #000080;">&lt;&lt;</span> i<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>first <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>运行结果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">cute kittens
ugly puppies
evil goblins
^Z
kittens are cute
goblins are evil
puppies are ugly</pre></div></div>

<p>上面例子中i的类型在编译时推演为 map<string, string>::iterator, 有了 auto 关键字你再也不用写又长又烦的代码了。（注意 m.begin() 返回类型是 iterator, 而不是 const_iterator, 因为这里的 m 并不是 const。C++0x 中的 cbegin() 能够解决这个问题，它返回 non-const 容器的 const 迭代器。）</p>
<p><strong>Lambda 表达式和 auto 关键字的配合</strong></p>
<p>上文中提到了用 tr1::functions 来存储 lambda 表达式，但是不建议那样做除非不得已，因为 tr1::functions 的开销问题。如果你需要复用 lambda 表达式或者像给它命名，那么 auto 是更好的选择。</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;algorithm&gt;</span>
<span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #339900;">#include &lt;ostream&gt;</span>
<span style="color: #339900;">#include &lt;vector&gt;</span>
&nbsp;
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">typename</span> T, <span style="color: #0000ff;">typename</span> Predicate<span style="color: #000080;">&gt;</span> <span style="color: #0000ff;">void</span> keep_if<span style="color: #008000;">&#40;</span>vector<span style="color: #000080;">&lt;</span>T<span style="color: #000080;">&gt;</span><span style="color: #000040;">&amp;</span> v, Predicate pred<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">auto</span> notpred <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #000040;">&amp;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> T<span style="color: #000040;">&amp;</span> t<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #000040;">!</span>pred<span style="color: #008000;">&#40;</span>t<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
    v.<span style="color: #007788;">erase</span><span style="color: #008000;">&#40;</span>remove_if<span style="color: #008000;">&#40;</span>v.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, notpred<span style="color: #008000;">&#41;</span>, v.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">typename</span> Container<span style="color: #000080;">&gt;</span> <span style="color: #0000ff;">void</span> print<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> Container<span style="color: #000040;">&amp;</span> c<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    for_each<span style="color: #008000;">&#40;</span>c.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, c.<span style="color: #007788;">end</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">typename</span> Container<span style="color: #008080;">::</span><span style="color: #007788;">value_type</span><span style="color: #000040;">&amp;</span> e<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> e <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> endl<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> a<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">100</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        a.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span><span style="color: #000080;">&gt;</span> b<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">100</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">200</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
        b.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">auto</span> prime <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> n<span style="color: #008000;">&#41;</span> <span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span> <span style="color: #0000ff;">bool</span> <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>n <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
&nbsp;
        <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;=</span> n <span style="color: #000040;">/</span> i<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
            <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>n <span style="color: #000040;">%</span> i <span style="color: #000080;">==</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
                <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #008080;">;</span>
            <span style="color: #008000;">&#125;</span>
        <span style="color: #008000;">&#125;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
    keep_if<span style="color: #008000;">&#40;</span>a, prime<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    keep_if<span style="color: #008000;">&#40;</span>b, prime<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    print<span style="color: #008000;">&#40;</span>a<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    print<span style="color: #008000;">&#40;</span>b<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>运行结果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">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
101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199</pre></div></div>

<p>上面代码中 notpred 是一个 lambda 表达式的否定式。这个例子中我们不能够使用 C++ 98 的 not1()，因为 not1 要求你的谓词是从 unary_function 派生的，但是 lambda 并不要求这点，所以很多情况下使用 lambda 更灵活。</p>
<h3>静态断言 static_assert</h3>
<p>断言（assertion）是提高代码质量的有效武器。C++标准库中的 assert、MFC 中的 ASSERT /VERIFY 宏都是断言的例子，它们的共同点是在运行时对程序状态进行判断，例如检查函数的参数有效性、检查类的不变式等。而 C++ 0x 中的静态断言呢，和运行时的断言不一样，它是编译时执行检查的。看下面的例子：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">template</span> <span style="color: #000080;">&lt;</span><span style="color: #0000ff;">int</span> N<span style="color: #000080;">&gt;</span> <span style="color: #0000ff;">struct</span> Kitten <span style="color: #008000;">&#123;</span>
static_assert<span style="color: #008000;">&#40;</span>N <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">2</span>, <span style="color: #FF0000;">&quot;Kitten&lt;N&gt; requires N &lt; 2.&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span>
    Kitten<span style="color: #000080;">&lt;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&gt;</span> peppermint<span style="color: #008080;">;</span>
    Kitten<span style="color: #000080;">&lt;</span><span style="color: #0000dd;">3</span><span style="color: #000080;">&gt;</span> jazz<span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>编译结果如下：</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">staticfluffykitten.cpp(2) : error C2338: Kitten&lt;N&gt; requires N &lt; 2.
        staticfluffykitten.cpp(8) : see reference to class template instantiation 'Kitten&lt;N&gt;' being compiled
        with
        [
            N=3
        ]</pre></div></div>

<p>上面例子中用 static_assert 对模板参数 N 进行了检查，如果断言失败编译器将使用用户自定义的错误消息。</p>
<p>Related posts:<ul>
<li><a href='http://wutiam.net/2009/06/uninstalling-visual-studio-2008-may-fail-to-load-setup-components/' rel='bookmark' title='Visual Studio 2008 无法进入修复/卸载界面的解决办法'>Visual Studio 2008 无法进入修复/卸载界面的解决办法</a></li>
<li><a href='http://wutiam.net/2009/04/some-vs2005-and-vs2008-wizards-pop-up-script-error/' rel='bookmark' title='IE8 引发 VS 2005/2008 向导出错的解决方案'>IE8 引发 VS 2005/2008 向导出错的解决方案</a></li>
<li><a href='http://wutiam.net/2009/05/msg-response-for-dynamic-created-ctreectrl-instance/' rel='bookmark' title='动态创建的 CTreeCtrl 实例的消息响应'>动态创建的 CTreeCtrl 实例的消息响应</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://wutiam.net/2010/06/lambdas-auto-and-static-assert-c-0x-features-in-vc10/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

