<?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:trackback="http://madskills.com/public/xml/rss/module/trackback/"><channel><title>Be Yourself And Beyond Yourself</title><link>http://www.i170.com/user/killercat/Rss</link><description></description><language>zh-cn</language><pubDate>Fri, 10 Feb 2012 00:24:53  +0800</pubDate><generator>i170.com</generator><image><title>Be Yourself And Beyond Yourself</title><url>http://www.i170.comattavatar_1/killercat_Src.JPG</url><link>http://www.i170.com/user/killercat/Rss</link></image> <item><link>http://www.i170.com/Article/120107</link><title><![CDATA[Something]]></title><author>killercat</author><category></category><pubDate>Tue, 05 Jan 2010 08:19:37  +0800</pubDate><description><![CDATA[<p>&nbsp;<img width="301" height="450" alt="" src=
"http://www.i170.com/Attach/65FB14A0-D298-4900-A79E-92C96DBC7E7F"></p>

]]></description><guid>http://www.i170.com/Article/120107</guid><trackback:ping>http://www.i170.com/Article/120107/trackback</trackback:ping><comments>http://www.i170.com/Article/120107#comment</comments><wfw:commentRss>http://www.i170.com/Article/120107/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/117053</link><title><![CDATA[C++ 构造函数]]></title><author>killercat</author><category>C/C++</category><pubDate>Sat, 30 May 2009 15:33:24  +0800</pubDate><description><![CDATA[<p>C++ 的构造函数是一个比较特殊的函数：</p>
<p>1）构造函数没有返回值，报告构造函数错误的最常见方法是抛出异常，其他方法都不靠谱，例如：</p>
<p>A::A(int&amp; error)</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;// ...</p>
<p>&nbsp;&nbsp; &nbsp;if (错误) error = -1;</p>
<p>}</p>
<p>2）构造函数中抛出异常，所有的父类的析构函数将被调用，但是本类的析构函数不会被调用。</p>
<p>3）构造函数中抛出异常，分配的空间将被自动释放。</p>
<p>4）在构造函数里面，虚函数将没有 virtual
特性，如果直接或者间接调用了一个未实现的纯虚函数，将导致未定义行为。因此不要在构造函数中调用虚函数。</p>

]]></description><guid>http://www.i170.com/Article/117053</guid><trackback:ping>http://www.i170.com/Article/117053/trackback</trackback:ping><comments>http://www.i170.com/Article/117053#comment</comments><wfw:commentRss>http://www.i170.com/Article/117053/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/116559</link><title><![CDATA[RAII]]></title><author>killercat</author><category>C/C++,Other</category><pubDate>Mon, 04 May 2009 12:35:31  +0800</pubDate><description><![CDATA[<div class="Section0" style="layout-grid:15.6000pt;">
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
对于资源，这里我分为两类：</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
1. 内存资源</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
2. 非内存资源（文件、网络资源等）</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
C++ 对于内存资源的管理部分是自动的：栈上的内存资源将被自动释放，堆上的内存资源需要程序员自己释放。</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
手动管理内存资源，总会让我们在一些极端情况下犯错。一个最简单，最常见的例子如下：</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
void f()</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
{ &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;A* a = new A(); &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;B* b = new B(); &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;C* c = new C(); &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// ... &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;if (某种条件) &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// 失败时 &nbsp; &nbsp; &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;delete a; &nbsp; &nbsp;
&nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;delete b; &nbsp; &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;delete c; &nbsp; &nbsp;
&nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// ... &nbsp; &nbsp; &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return; &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// 成功继续处理 &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;Z* z = new Z(); &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;try &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;f2();&nbsp;// f2 可能抛出异常
&nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} catch (const xxx&amp;) { &nbsp; &nbsp; &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;delete a; &nbsp; &nbsp;
&nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;delete b; &nbsp; &nbsp;
&nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;delete c; &nbsp; &nbsp;
&nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// 忘记释放 z &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// 没有异常继续处理</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
不论是多么优秀的程序员，他也不能保证永远正确的释放了内存资源，遇见上面情况的解决办法之一就是使用
autoptr，我们可以这样写：</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
void f()</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
{ &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;autoptr&lt;A&gt; a(new A()); &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;autoptr&lt;B&gt; b(new B()); &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;autoptr&lt;C&gt; c(new C()); &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// ...</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;if (某种条件) &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// 失败时，无需释放资源 &nbsp; &nbsp;
&nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return; &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// 成功继续处理 &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;autoptr&lt;Z&gt; z(new Z());</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;try &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;f2(); // f2 可能抛出异常 &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} catch (const xxx&amp;) { &nbsp; &nbsp; &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// 无需释放资源 &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// 没有异常继续处理</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
不错，这看起来很完美，我们解决了异常情况下内存资源释放的问题。但是，对于非内存资源呢？例如：</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
void f()</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
{ &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;FILE* pf1 = fopen("killercat.blog1", "w");</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;FILE* pf2 = fopen("killercat.blog2", "w");</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;FILE* pf3 = fopen("killercat.blog3", "w");</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// ... &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;try</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;f2(); // f2 可能抛出异常 &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} catch (const xxx&amp;) { &nbsp; &nbsp; &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fclose(pf1); // 又回到了丑陋的代码</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fclose(pf2);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fclose(pf3); &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
很显然，FILE 不是一个类，我们无法使用诸如 autoptr
这样的管理器来进行资源的生命周期管理，对非内存资源的生命周期的管理，我们有另外一种方式可循：把非内存资源的生命周期的管理转化为内存资源的生命周期的管理。</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
RAII（Resource Acquisition Is
Initialization），资源（这里的资源通常是指的是非内存资源）获取即使初始化，换而言之，我们将利用 C++
构造函数和析构函数来维护一个不变式（invariant）：对象存在则资源（常常指非内存资源也可以只内存资源）有效。一个经典的例子就是：</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
// use an object to represent a resource ("resource acquisition is
initialization")</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
class File_handle</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// belongs in some support library</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;FILE* p;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
public:</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;File_handle(const char* pp, const char* r)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;p = fopen(pp,r);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (p==0)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;throw
Cannot_open(pp);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;File_handle(const string&amp; s, const char*
r)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;p = fopen(s.c_str(),r);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (p==0)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;throw
Cannot_open(pp);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;~File_handle()</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fclose(p);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} // destructor</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// copy operations and access functions</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
};</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
void f(string s)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;File_handle file(s, "r");</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// use file</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
从上面的 File_handle 类可以看出，构造对象的时候，我们初始化非内存资源 FILE，当对象释放时，FILE
同时被释放。</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
通过 RAII 我们能够将非内存资源生命周期管理转换到内存资源生命周期的管理上来，那么上面丑陋的代码转化为：</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
void f()</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
{ &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;autoptr&lt;File_handle&gt; pf1(new
File_handle("killercat.blog1", "w"));</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;autoptr&lt;File_handle&gt; pf2(new
File_handle("killercat.blog2", "w"));</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;autoptr&lt;File_handle&gt; pf3(new
File_handle("killercat.blog3", "w"));</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// ... &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;try &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;f2(); // f2 可能抛出异常 &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} catch (const xxx&amp;) { &nbsp; &nbsp; &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// 资源能够被正确释放 &nbsp;
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;</p>
<p class="p0" style=
"line-height: 1.4em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;">
<span class="Apple-style-span" style="color: rgb(255, 0, 0);">RAII
的实质：</span></p>
<p class="p0" style=
"line-height: 1.4em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;">
<span class="Apple-style-span" style="color: rgb(255, 0, 0);">1.
通过把非内存资源的生命周期管理转化为内存资源的生命周期管理，达到对非内存资源的安全释放。</span></p>
<p class="p0" style=
"line-height: 1.4em; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;">
<span class="Apple-style-span" style="color: rgb(255, 0, 0);">2.
通过维护一个 invariant（对象存在即资源有效），来简化编程。</span></p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
当然，这里不仅仅可以使用 autoptr 也可以使用 shared_ptr 等智能指针。不过，除此之外，RAII 还维护了一个
invariant --- 对象存在即资源有效，invariant 的出现，必定带来一个结果：简化编程。看下面的例子：</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
class File_handle</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;FILE* p;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
public:</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;File_handle(const char* pp, const char* r)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;p = fopen(pp,r);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (p==0)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;throw
Cannot_open(pp);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;File_handle(const string&amp; s, const char*
r)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;p = fopen(s.c_str(),r);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (p==0)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;throw
Cannot_open(pp);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;~File_handle()</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fclose(p);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} // destructor</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;int GetChar()</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// 无需检查 p，因为 p 一定有效</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return fgetc(p);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
};</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
我们可以看到，在对象存在的时候，文件资源总是有效的，因为我们无需判断指针 p
是否合法，这简化了编程，使得代码更加优雅。相比之下，这样实现就不那么美观：</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
class File_handle</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;FILE* p;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
public:</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;File_handle()</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// 必须初始化为
NULL，否则下面的所有检查将无效，代码将非常脆弱</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;p = NULL;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;~File_handle() {}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;void Open(const char* pp, const char* r)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// 必须判断，是否调用两次 Open</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (p == NULL)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;p =
fopen(pp,r);&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(p==0)&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;throw Cannot_open(pp);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;throw
Close_first();</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;void Close()</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (p != NULL)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;fclose(p);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//
必须置空，否则程序其他地方判断将失效</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;p ==
NULL;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;throw
Open_first();</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;int GetChar()</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// 类似于 GetChar 的函数都需要判断，否则在调用
Open 之前调用程序将出错</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (p != NULL)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return
fgetc(p);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;throw
Open_first();</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
};</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
显而易见，对于资源是否有效的判断已经使得程序员是否疲惫，而且，他们还需要不停的维护资源的指针，只要任何一步出错，程序都将变得脆弱，更作用的是，不但编写这样的程序不会有任何快感，使用这样的代码也十分郁闷，比如调用&nbsp;GetChar
的时候，需要当心函数抛出的来异常，不断的写 try catch（如果使用 error codes
来表示错误，也需要不断的判断函数执行是否出错），在一些复杂的情况下，更加让人抓狂：</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
bool AddGroup(int idUser)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// 检查 idUser 是否允许加入组</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// ...</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// 检查成功，允许加入，扣去入会费</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;SpendUserMoney(idUser, 10000);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// 对于入会成功用户增加一个等级</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;AddUserLevel(idUser);&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// 等等操作</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;// 将其写入文件中</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;try</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;// 在文件中写入用户当前等级，入会花费等信息</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;file.Write("xxx");</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;} catch (const&nbsp;Open_first&amp;)</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;{</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;// 异常出现</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;// 恢复现场</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;AwardUserMoney(10000);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ReduceUserLevel(idUser);</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;// 等等</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;&nbsp; &nbsp;}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
}</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
由上例可见，为了处理异常情况而做的工作太大，而且我们每次调用时都要进行相似的处理。虽然上例不一定完全合乎实际情况，或许你认为它还有改良的空间，不过无论如何，我们难免要做太多多余的工作。</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
&nbsp;</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
自此，已经谈完了 RAII 设计方式的好处，那么下面谈谈应该注意一些什么：</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
1. 如果没有必要，应该禁止复制。</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
如果没有必要应该禁用复制构造函数和赋值操作符，这点很重要，如果没有按需要定义复制构造函数和赋值操作符，那么得到的结果通常是：非内存资源被创建一次，释放多次。</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
2. 如果需要复制，应该谨慎考虑。</p>
<p class="p0" style=
"margin-bottom:0pt; margin-top:0pt; padding:0pt 0pt 0pt 0pt ; text-autospace:ideograph-other;">
重新定义复制构造函数和赋值操作符是必须的。怎么写它们是一个问题，具体的方案依赖于实际的需要，可以使用深拷贝，也可以使用类似于
shared_ptr 的引用计数机制，或者传递所有权。</p>
<p>&nbsp;</p>
<p><span class="Apple-style-span" style=
"color: rgb(255, 0, 0);">总结一下：</span></p>
<p><span class="Apple-style-span" style="color: rgb(255, 0, 0);">1.
使用 RAII 能够将非内存资源的生命周期管理转为内存资源生命周期的管理，使得我们能够使用管理内存资源的手段来管理非内存资源，例如
auto_ptr，shared_ptr。</span></p>
<p><span class="Apple-style-span" style="color: rgb(255, 0, 0);">2.
维护 invariant 能够简化编程，使的代码简洁优雅。RAII 设计方式维护了这么一条
invariant：对象存在则资源有效。除此之外，我们还可以使用异常机制来维护另外一条
invariant：函数要么执行成功得到正确的结果，要么抛出异常。对此条，这里就不做任何阐述了。</span></p>
<p><span class="Apple-style-span" style="color: rgb(255, 0, 0);">3.
使用 RAII 时，应该警惕复制行为。<br></span></p>
</div>

]]></description><guid>http://www.i170.com/Article/116559</guid><trackback:ping>http://www.i170.com/Article/116559/trackback</trackback:ping><comments>http://www.i170.com/Article/116559#comment</comments><wfw:commentRss>http://www.i170.com/Article/116559/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/115986</link><title><![CDATA[模块间的关联]]></title><author>killercat</author><category>设计</category><pubDate>Mon, 06 Apr 2009 17:13:40  +0800</pubDate><description><![CDATA[<p>
模块间的关联不但应该少，而且应该清晰（clean），当保持更少的接口和更清晰的接口之间存在矛盾时，应该优先考虑使用清晰而不是更少的接口。</p>

]]></description><guid>http://www.i170.com/Article/115986</guid><trackback:ping>http://www.i170.com/Article/115986/trackback</trackback:ping><comments>http://www.i170.com/Article/115986#comment</comments><wfw:commentRss>http://www.i170.com/Article/115986/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/115829</link><title><![CDATA[使用异常代替错误码]]></title><author>killercat</author><category>C/C++,设计</category><pubDate>Sun, 29 Mar 2009 19:23:48  +0800</pubDate><description><![CDATA[<p>函数的输出和错误信息通常被不加思考的混合在一起。例如，大家可能经常写这么一个函数：</p>
<p>int f(); // 如果返回 0 表示错误，正常的返回值大于 0</p>
<p>上面这个函数很显然把函数的结果和错误信息混合在一起了，那么如果我们出现这样的函数：</p>
<p>int Div(const int num1, const int num2); // 两个数相除</p>
<p>如果 num2 为 0 那么必定引起错误，这个时候，应该用什么值来表示错误？用 0 吗？显然 0
属于合理的输出区间，不能用来表示错误。其实，我们没有办法用任何数字来表示这个错误。作为改进，可以使用这样的办法：</p>
<p>bool Div(const int num1, const int num2, int&amp; res); //
使用输出参数 res</p>
<p>显然，我们把函数结果和错误信息分开了。看下面一个函数：</p>
<p>bool Save(const Data&amp; data, int&amp; index); // 这个函数用来保存数据
data 到磁盘中并且返回一个在磁盘中索引文件的 index，这个 intdex 可以为任何整数。</p>
<p>这里，我们使用了 bool
表示操作的是否成功。然而情况可能比较复杂，失败可能由多种情况引起，我们需要知道是什么原因，以便进行相应的处理。所以，我们改造一下：</p>
<p>int Save(const Data&amp; data, int&amp; index); // int
表示错误的类型</p>
<p>&nbsp;</p>
<p>在对软件可靠性要求非常高的程序中，我们会关注每一个可能发生的错误，比如 new
失败等。我们不能去忽视那些应该面对的异常现象。因此，这里首先需要做一个约定：每个函数都应该分离错误信息和函数的输出。这个约定应该是高可靠性软件开发中必须要遵循的约定，否则开发者可能按照习惯编写出&nbsp;int
Div(const int num1, const int num2)
之类的函数，对于那种自己觉得很难发生的异常现象，从心理上拒绝或者偷懒，如果真的出现有人这样调用 Div(10, 0)
那么他大概会开始埋怨调用者的无知了，而不是自己的函数无法包容错误的输入。</p>
<p>那么，我们现在有多种选择，第一个，就是用 int 作为每一个函数的返回值，然后用输出参数来处理函数的输出。例如：</p>
<p>int Div(const int num1, const int num2, int&amp; out);</p>
<p>要么提供 GetLastError 和 SetLastError 的函数：</p>
<p>int g_error;</p>
<p>int GetLastError() { return g_error; }</p>
<p>void SetLastError(const int error) { g_error = error; }</p>
<p>来管理错误。实现 Div：</p>
<p>int Div(const int num1, const int num2)</p>
<p>{</p>
<p>&nbsp;&nbsp; if (num2 == 0)</p>
<p>&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;SetLastError(1); // 1 表示除 0
的异常</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return 0;</p>
<p>&nbsp;&nbsp; &nbsp;}</p>
<p>&nbsp;&nbsp; &nbsp;SetLastError(0); // 表示成功</p>
<p>&nbsp;&nbsp; &nbsp;return num1 / num2;</p>
<p>}</p>
<p>此外也许还有很多方式，但是在 C++ 中一种更好的方式是使用异常。</p>
<p>使用异常处理异常情况可以做出一个保证，如果函数能够输出值，那么它一定输出一个正确的值，否则就是异常情况出现了。</p>
<p>异常是语言内建的一种机制。如果我们使用返回值来标识错误：</p>
<p>int f1()</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;if (x)</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return EXC_1; // 异常情况 1</p>
<p>&nbsp;&nbsp; &nbsp;if (y)</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return EXC_2; // 异常情况 2</p>
<p>}</p>
<p>int f2()</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;int exc = f1(); // 调用 f1</p>
<p>&nbsp;&nbsp; &nbsp;if (exc == EXC_1) // f2 函数对于 f1
的失败很无奈，它无法处理只能告诉上层</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return EXC_1;</p>
<p>&nbsp;&nbsp; &nbsp;if (exc == EXC_2)</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return EXC_2;</p>
<p>&nbsp;&nbsp; &nbsp;if (z) // 自己可能发生的问题</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return EXC_3;</p>
<p>}</p>
<p>我们可以想象，有时候对于这种处理是很痛苦的，但是又不得不这么处理。特别是：</p>
<p>bool IsGood()</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;// ... 一些操作</p>
<p>}</p>
<p>现在需要变化，导致我们需要改变 IsGood 的实现，IsGood 需要调用到 f2，那么：</p>
<p>bool IsGood()</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;int exc = f2();</p>
<p>&nbsp;&nbsp; &nbsp;exc ... // 怎么告诉上层出现了什么错误？返回值为 bool</p>
<p>}</p>
<p>除非我们去改变 IsGood 函数的原型，否则上层将无法得到任何异常的信息（在需要的时候），而改变接口的代价是巨大的。</p>
<p>
换过来想想异常处理，一切问题都不存在。我们能够借助异常机制，编写极其健壮的代码，编写出只要操作系统不崩溃，那么就不会崩溃的程序。很多书籍指出异常将导致整个系统复杂度增加，这是毋庸置疑的，但是要明白的是，程序中本来就存在很多隐患，只是这些隐患只在极端的情况下发生，于是乎大多数人把它忽略掉，以求得一个“简单”的系统，事实上，无论使不使用异常机制，异常现象都是存在的。当你要让你的程序包容任何异常问题时，使用异常机制绝对是一个好的选择。</p>

]]></description><guid>http://www.i170.com/Article/115829</guid><trackback:ping>http://www.i170.com/Article/115829/trackback</trackback:ping><comments>http://www.i170.com/Article/115829#comment</comments><wfw:commentRss>http://www.i170.com/Article/115829/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/115824</link><title><![CDATA[设计之子程序（Routine）]]></title><author>killercat</author><category>设计</category><pubDate>Sun, 29 Mar 2009 15:04:54  +0800</pubDate><description><![CDATA[<p>我们把函数，方法，过程（Procedure），宏等统一叫做子程序（Routine）。</p>
<p>子程序的最大的两个用途：</p>
<p>1）隐藏信息</p>
<p>2）避免重复代码</p>
<p>&nbsp;</p>
<p>1. 隐藏信息</p>
<p>
隐藏信息是子程序的一种功能，但是只有命名合理的子程序才具有此项功能，命名合理即：子程序以及参数的名称能够反映出子程序的含义。</p>
<p>子程序能够隐藏信息，特别用于隐藏以下几种信息：</p>
<p>&lt;1&gt; 复杂的嵌套信息</p>
<p>如果出现复杂的 for 或者 if 嵌套而又不可避免，那么可以把深层的嵌套放入一个子程序中来完成，例如：</p>
<p>for (int i=0; i&lt;MAX; ++i)</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;if (xxx)</p>
<p>&nbsp;&nbsp; &nbsp;{</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (yyy)</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;{</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;zzz;</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</p>
<p>&nbsp;&nbsp; &nbsp;}</p>
<p>}</p>
<p>这个时候，if
语句可以放入一个命名合理的子程序中，这样对于阅读者或者开发者来说程序更加容易理解或编写。这时，子程序的名字和参数是对子程序含义的一个说明，因此，如果你编写子程序的目的在于隐藏信息，那么你就必须提供足够的能够清楚反映子程序功能的名称。</p>
<p>&lt;2&gt; 顺序信息</p>
<p>执行某些操作需要按一定顺序进行，我们可以通过一个子程序来隐藏这种顺序：</p>
<p>IDevice* device = createDevice();</p>
<p>device-&gt;Init(); // 必须最先调用</p>
<p>device-&gt;CreateXXX(); // 必须在调用 Init 之后调用</p>
<p>device-&gt;CreateYYY(); // 必须在调用 CreateXXX 之后调用</p>
<p>那么，我们可以把上面的操作放入一个子程序中，让子程序来隐藏调用的顺序信息。</p>
<p>2. 避免重复代码</p>
<p>“重复”一词在程序设计中总是不太好的东西，重复计算带来额外的消耗，例如：</p>
<p>int f(int n)</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;if (n == 1 || n == 0) return 1;</p>
<p>&nbsp;&nbsp; &nbsp;else</p>
<p>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return f(n - 1) * f(n - 2);</p>
<p>}</p>
<p>这是一个典型的低效的递归函数，很明显，我们计算 f(n - 1) * f(n - 2) 的时候，在计算 f(n - 1)
时需要计算一次 f(n - 2)，后面 * f(n - 2) 时，又计算了一次 f(n - 2)
这种重复计算是导致效率低下的根本。</p>
<p>同样，重复的数据出现，导致数据同步的麻烦：</p>
<p>class User</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;string name; // 玩家名字</p>
<p>}</p>
<p>class Flower</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;string userName; // 送花的玩家的名字</p>
<p>}</p>
<p>
我们在一个送花系统中保存了送花玩家的名字，如果玩家改名了，那么我们需要同时改变送花系统中记录的玩家的名字，这显然是麻烦的。</p>
<p>当然，现在要讲到的重复，不是计算重复，也不是数据重复，而是代码重复。代码重复和数据重复一样，代码的后果是 ---
惧怕变化。例如：</p>
<p>void f1() { XXX; A; YYY; } // A 表示一段代码</p>
<p>void f2() { A; ZZZ; } // &nbsp;A 同于上面表示的代码</p>
<p>那么，如果系统由于某些原因需要改变，导致 A 发生变化，那么变化将影响到 f1, f2 两个函数。</p>
<p>
另外，重复代码带来阅读上的不方便，特别是程序中含有大量相似代码时，阅读很困难，这时候，应该提取相似代码的共性，放入一个子程序中。</p>
<p>&nbsp;</p>
<p>误区：不要认为子程序的只是用来避免重复代码的，换而言之，有一些程序员可能认为，只有 1，2
行并且也只在一个地方出现的代码不应该做成一个子程序。这种观点是不正确的，子程序有时候充当一种注释的角色：</p>
<p>int GetID() { return m_id % 1000; } // m_id 的后 3 位表示 id 号</p>
<p>在程序中使用 GetID 来代替 m_id % 1000 将更加好读。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>内聚性，子程序中各个操作之间的关联的紧密程度，如果子程序中各个操作关联非常紧密，那么我们称之为高内聚，相反位低内聚。pow
这样的函数是高内聚的，而诸如 SetAttr(int value, bool synchro); 这样的函数内聚性就稍低。</p>
<p>为什么一个子程序只做一件事是好的（KISS）？</p>
<p>
只做一件事情的子程序是高内聚的。这种程序不容易出错（据调查研究得知），另外这样的程序很好命名，那么从子程序的外层（调用者一层）和子程序的内层（子程序内部）来看，可读性都是高的。</p>
<p>&nbsp;</p>
<p>参数问题：</p>
<p>子程序的参数可能只是用来使用，而不会被修改的参数，这被叫做输入参数；</p>
<p>如果参数只是用于返回值出去，而子程序不使用它的值，这种参数叫做输出参数；</p>
<p>如果参数的值将被子程序使用并且会修改它，这种参数叫做修改参数。</p>
<p>我们可以规定一个参数的排列顺序：输入 --- 修改 --- 输出。这种统一的风格，可以使得代码更加可读。</p>
<p>在 C++ 中，我们可以使用关键字 const
来标明参数为输入参数，使用引用类型（或者指针）来表明参数是一个修改或者输出参数（你甚至可以规定，修改参数使用指针类型，输出参数使用引用类型），例如：</p>
<p>bool Add(const int num1, const int num2, int&amp; res); // num1
和 num2 为输入参数，res 为输出参数</p>
<p>Windows 下做 C++ 开发的程序员很喜欢使用 IN OUT，例如：</p>
<p>bool Add(IN int num1, IN int num2, OUT int&amp; res); // 同上</p>
<p>IN，OUT 的缺点在于，它不是语言的一部分，那么如果有这么一个函数：</p>
<p>void f(IN User&amp; user); // user 是一个输入参数</p>
<p>在某些情况下，需求变化了，某个代码的维护人员修改了 f 函数的实现，使得 user 变成了一个修改参数，而 IN 没有被改为
IN OUT，这样必定给代码阅读着带来疑惑，而且编译器也不会去警告开发者。</p>
<p>很多人不愿意使用 const 去修饰输入参数，他们觉得这是多余的，但是我们看下面的程序：</p>
<p>int f(int num)</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;// .... 很多操作，num 被到处使用，这时候你无法确保 num
会不会被修改</p>
<p>}</p>
<p>如果这个函数比较长（我见过 2000 多行的），里面的逻辑比较复杂，你在维护代码时，也许你需要最初传入的 num
的值，但是你又很难确保 num 没有被修改。</p>
<p>&nbsp;</p>
<p>关于函数返回值的一个议题：</p>
<p>我们应该使用 ---</p>
<p>int Add(const int num1, const int num2);</p>
<p>还是 ---</p>
<p>bool Add(const int num1, const int num2, int&amp; res);</p>
<p>这是一个值得考虑的问题，尤其是在软件可靠性变得异常重要的时候，在一些极端的环境中，完全正常的程序可能就失效了。</p>
<p>为此，我做了仔细的思考，并且把有关的问题陈述于此：<a href=
"http://www.i170.com/user/killercat/Article_115829">http://www.i170.com/user/killercat/Article_115829</a></p>
<p>另外，这里还有一篇可以参考的文章：<a href=
"http://wesleybao.spaces.live.com/Blog/cns!1p0i3yoUKRgnWt0UyAV1FMog!935.entry">http://wesleybao.spaces.live.com/Blog/cns!1p0i3yoUKRgnWt0UyAV1FMog!935.entry</a>&nbsp;</p>

]]></description><guid>http://www.i170.com/Article/115824</guid><trackback:ping>http://www.i170.com/Article/115824/trackback</trackback:ping><comments>http://www.i170.com/Article/115824#comment</comments><wfw:commentRss>http://www.i170.com/Article/115824/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/115731</link><title><![CDATA[阅读代码的基本观念]]></title><author>killercat</author><category>C/C++</category><pubDate>Wed, 25 Mar 2009 03:04:47  +0800</pubDate><description><![CDATA[<p>我们经常需要去阅读大量代码，遵循一些经过验证的规则有利于我们更好的阅读代码。</p>
<p>1、阅读代码应该以 Routine 为单位。在阅读某个 Routine 时，应该理解其实现，当在其他地方调用此 Routine
时，你无需回忆此 Routine 的实现细节（甚至应该忘记具体细节），但是你必须知道此 Routine 的含义，详细来说，包括
Routine 的参数和返回值以及 Routine 本身的含义。你的每个接触的 Routine
及其参数的含义的熟练程度，直接影响到你阅读代码的速度。</p>
<p>低质量代码标志：Routine 的名称无法反映其含义，参数名称无法反映参数含义，出现多个名称类似的无法区分含义
Routine，例如：</p>
<p>bool IsTypeValid(int typeID); // 用于检查数据库中是否存在此&nbsp;typeID</p>
<p>bool CheckType(int typeID); // 用于检查 typeID 是否处于合理的区间</p>
<p>我们很难从名字上区分两个函数的含义。</p>
<p>好的命名是：即使我们忘记了 Routine 的实现，但是我们也能通过名字很明确的知道 Routine（以及参数）的含义。</p>
<p>2、如果出现共享数据，那么就需要去理解它的含义。</p>
<p>低质量代码标志：共享数据泛滥，你很难确定某个数据到底什么时候被赋值，代码难以阅读和维护。</p>
<p>3、总结代码中的惯用法。代码中，总会留有作者的编写代码的一些习惯，总结这些编写习惯，能够提高理解代码的速度。例如：</p>
<p>笔者见过的一个作者非常喜欢使用的一种手法，这里先不讨论这种做法是否合理：</p>
<p>int g_id;</p>
<p>void SetID(int id)</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;g_id &amp;= 0xFF00;</p>
<p>&nbsp;&nbsp; &nbsp;g_id |= (id &amp; 0x00FF);</p>
<p>}</p>
<p>void SetIDType(int type)</p>
<p>{</p>
<p>&nbsp;&nbsp; &nbsp;g_id &amp;= 0x00FF;</p>
<p>&nbsp;&nbsp; &nbsp;g_id |= (type &amp; 0x00FF);</p>
<p>}</p>
<p>上面的代码，没什么经验的程序员初次见到一定是一头雾水，它实际上把一个 int 变量分成了 2 部分，一部分用来保存 id
的值，一部分用来保存 id
类型的值。其目的之一在于节约内存。很明显，如果读者不知道作者的惯用法，不去总结作者的惯用法，那么在读代码时非常容易一头雾水，越读越糊涂。</p>
<p>
低质量代码标志：读者通常最无法忍受的是没有统一风格的代码，同种设计思想使用不同的写法，不同的命名风格，没有章法的参数排列等等。</p>
<p>
4、读代码只能精读。代码不如小说，即使一目十行也能看个梗概。代码不如文字，即使再怎么显而易见，也需要读者一行一行仔细看下去。</p>

]]></description><guid>http://www.i170.com/Article/115731</guid><trackback:ping>http://www.i170.com/Article/115731/trackback</trackback:ping><comments>http://www.i170.com/Article/115731#comment</comments><wfw:commentRss>http://www.i170.com/Article/115731/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/115662</link><title><![CDATA[分析链接错误（C++）]]></title><author>killercat</author><category>C/C++</category><pubDate>Sat, 21 Mar 2009 14:20:11  +0800</pubDate><description><![CDATA[<div style=
"padding-right: 4px; padding-left: 4px; font-size: 12px; padding-bottom: 4px; margin: 0px; border-top-style: none; line-height: 1.4em; padding-top: 4px; font-family: Tahoma, Verdana, sans-serif; border-right-style: none; border-left-style: none; background-color: rgb(255,255,255); border-bottom-style: none">
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
1. 错误根源</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
链接时，链接器需要寻找程序所引用的标识符，如果在所有的库文件（.lib）和目标文件（.obj）中找不到就会产生链接错误。</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
2. 引起错误的常见原因：</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
1）工程内函数只声明而没有定义：</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
C++ 允许函数声明而不用定义，例如：</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
&nbsp;</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
int Add(int, int); // Add 没有定义</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
int main()</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
{}</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
但是如果我们需要调用 Add 函数，即：</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
int main()</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
{</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
&nbsp;&nbsp; &nbsp;Add(1, 1); // 找不到标识符，链接错误</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
}</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
最常见的情况是，类成员函数只声明而没有定义。更为微妙的情形是：</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
我们有一个接口：</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
class IUser</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
{</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
public:</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
&nbsp;&nbsp; &nbsp;virtual int GetID() const = 0;</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
&nbsp;&nbsp; &nbsp;virtual void SetID(const int id); // 这里不小心漏掉了 =
0</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
};</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
class User : public IUser // 实现类</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
{</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
protected:</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
&nbsp;&nbsp; &nbsp;virtual int GetID() const;</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
&nbsp;&nbsp; &nbsp;virtual void SetID(const int id);</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
};</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
// User 的实现略</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
int main()</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
{</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
&nbsp;&nbsp; &nbsp;// ...</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
&nbsp;&nbsp; &nbsp;IUser* user = GetUser(id);</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
&nbsp;&nbsp; &nbsp;user-&gt;SetID(1); // 注意这里</p>
<p style=
"padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; line-height: 1.4em; padding-top: 0px">
}</p>
<p>&nbsp;</p>
</div>

]]></description><guid>http://www.i170.com/Article/115662</guid><trackback:ping>http://www.i170.com/Article/115662/trackback</trackback:ping><comments>http://www.i170.com/Article/115662#comment</comments><wfw:commentRss>http://www.i170.com/Article/115662/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/115324</link><title><![CDATA[推荐一个软件 TLB]]></title><author>killercat</author><category>Windows</category><pubDate>Sun, 08 Mar 2009 18:46:42  +0800</pubDate><description><![CDATA[<p>&nbsp;<a href="http://www.truelaunchbar.com/index.html">TLB ---
True Launch Bar</a></p>
<p>&nbsp;不多说，先看几张图：</p>
<p><img alt="" src=
"http://www.truelaunchbar.com/images/tlbscreen.jpg"></p>
<p><img alt="" src=
"http://www.truelaunchbar.com/images/tlbscreen3.jpg"></p>
<p><img alt="" src=
"http://www.truelaunchbar.com/images/tlbscreen2.jpg"></p>
<p>flash demo:</p>
<p><embed src="http://www.truelaunchbar.com/tlbtutor.swf" width=
"700" height="500" scale="showall" play="true" loop="true" menu=
"true" wmode="Window" quality="1" type=
"application/x-shockwave-flash"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>

]]></description><guid>http://www.i170.com/Article/115324</guid><trackback:ping>http://www.i170.com/Article/115324/trackback</trackback:ping><comments>http://www.i170.com/Article/115324#comment</comments><wfw:commentRss>http://www.i170.com/Article/115324/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/115179</link><title><![CDATA[[转载]清华梦的粉碎—写给清华大学的退学申请]]></title><author>killercat</author><category></category><pubDate>Sun, 01 Mar 2009 02:59:45  +0800</pubDate><description><![CDATA[<p>　&nbsp; 清华梦的诞生<br>
<br>
&nbsp;&nbsp;&nbsp;
小时候，妈妈给我一个梦。她指着一个大哥哥的照片对我说，这是爸爸的学生，他考上了清华大学，他是我们中学的骄傲。长大后，你也要进入清华大学读书，为我们家争光。我不知道清华是什么样子，但是我知道爱迪生和牛顿的故事。清华，大概就是可以把我造就成他们这种人的地方吧。我幼小的脑海里就想象出我能在清华做的事情......我的脸上浮现出笑容。我说我要实现这个"清华梦"。这就是清华梦的诞生。<br>

<br>
　　小小科学家<br>
<br>
　　我相信每个人在小时候都跟我差不多，对这个世界充满了好奇。<br>
<br>
　　鲁迅有他的百草园，我也有我自己的"实验田"。如果说小时候的鲁迅是一个艺术家，那么小时候的我就是一个科学家。这么说可能有人要说我口气太大，张口闭口就是这家那家。然而在我的字典里，"艺术家"和"科学家"并不是什么了不起的人，它们只是贴在人内心的一个标签。如果一个小孩专注于内心对世界的感觉，那么他就是一个艺术家。而我不是。我的大部分兴趣是在了解世界是怎样运转，甚至不惜代价。也许大部分男孩子都是这样。<br>

<br>
　　我小时候住在父母执教的中学里。两间平房，门口有一小块地，妈妈在里面种了一些菜。我们一家三口虽然穷，但是过着宁静舒适的生活。我们在这个地方一直住到上初中的时候。这些房屋记录着一个年幼的科学家的探索和实验，直到它们被夷为平地。<br>

<br>
　　妈妈拒绝让我养猫狗，她说凡是会拉屎的都不养---除了我。所以我小时候就喜欢与蚂蚁作伴。我总是试图用各种各样的办法去了解蚂蚁的生活习性。我可以一整天的观察我家屋檐下的蚂蚁来来去去。看见他们用触须碰一碰，然后各自分头走开，我就会想它们到底说了什么。我在想，能不能用一种方法解开蚂蚁语言的密码。我从书中得知蚂蚁洞里有蚁后，她有很大的肚子。为了一睹芳容，我开始试图水漫金山，把水往蚂蚁洞里灌。我有时一个下午就干这种事情，却没有一次成功看到蚁后。后来才知道蚂蚁是如此精明的下水道工程师，水大部分都渗到地底下去了。可是我不甘心，我开始试用别的办法。比如在洞口放一块糖。可是蚁后架子太大，终究不肯出来，让别人帮她送饭进去。<br>

<br>
　　有人说，这个世界最后不是毁在疯子手上，就是毁在科学家手上。世界上如果只有科学家是很可怕的，比如他们会发明高效的杀人武器。我发现疏松的棉絮可以迅速的燃烧，就想出一种惨绝蚁寰的大屠杀实验。我先把糖水滴在地上，等蚂蚁把那个地方围个水泄不通的时候，铺上棉花，点火......现在想起那些勤劳的小黑头都变成灰烬，我仍然心惊肉跳。他们的灵魂会来找我报复吗？后来这个实验有一个升级的版本用的是浸泡过一种化学药品溶液的纸，文火燃烧，由于燃烧速度慢，杀伤力不大，这个实验可以测试蚂蚁的逃跑路线。我还用活蚂蚁进行过心理实验。首先用破袜子摩擦塑料尺产生静电，然后放在一只正在行走的蚂蚁身后不远处。蚂蚁走不动了，我就开始推测它在想什么，它感觉到什么。它可能会觉得有外星人？但是由于尺子拿开以后，它若无其事继续走，我猜它只是有点纳闷，而不惊慌。但是反反复复几次之后，它明显有罢工的意思，似乎忘了自己要去干什么。后来我又发现蚂蚁被吸到塑料尺上之后会由于带上相同的电荷而被"发射"出去，就像人间大炮一样。注："人间大炮"是日本电视剧《恐龙特急克塞号》里的一种可以把人当作炮弹发射的威力很大的电磁装置。<br>

<br>
　　一点微小的发现，就可以引发大量的探索和实验。这就是我在那个年代的特点。虽然妈妈也逼着我练习毛笔书法，绘画，还多次获奖，但我不喜欢这些东西。我似乎生下来就是科学家，不是搞艺术的，不过也许只是妈妈的强迫让我反感了艺术而已。物理是我最喜欢的，因为它让我了解到世界的奥秘。我一般开学前几天就会把物理书上的实验都挑出来，费尽辛苦找到材料实践一番，心里美滋滋的。<br>

上学真是快乐！<br>
<br>
　　失之交臂<br>
<br>
　　上了高中，由于课业的压力，我的生活逐渐改变了。为了考上清华大学，我努力的学习。抛下我的毛笔书法，抛下我用来做实验的蚂蚁，电池和线圈，抛下除了考试科目的一切。在老师眼里我是一个听话的好学生，在妈妈眼里我是一个听话的好孩子。每天早上按时起床，吃一大碗妈妈做的面（为了补充一上午学习需要的体力），然后冲进教室，按照预设的程序开始读书，做练习题。似乎一切都有条不紊，顺利进行。可是......<br>

<br>
　　忽然有一天我发现，我的一切活动都是在纸上进行的，看书，做习题。试卷和复习书让我变得变得麻木。我想这样下去我就不再像爱迪生和牛顿了。于是我开始调皮起来。我不但要做考试的题目，还要做更难的题目。做了物理奥林匹克的题目，接着就想看大学的物理书，接着就想恢复我小时候的实验的爱好。老师辅导自习时经常被我缠住问一些不着边际的问题，那其实是我在实验中发现的问题。终于有一天，在我要求他跟我合作制造一个磁悬浮陀螺的时候，他显示出了不耐烦："王垠，你让我先回答别的同学的问题好不好？你的问题对考试没有好处。"<br>

<br>
　　我呆住了，启发我让我爱上物理的人，尽然对我说出这样的话。后来想一想，他也是无奈啊，不过我从此再也不想问他任何"超纲"的问题。<br>

<br>
　　高二的时候妈妈就拿回一份前一届的高考题让我做，我随手一做就得了一个当时可以考上清华的成绩。我的心里想，清华我来了。明年的这个时候，我就会拿到录取通知书了！从此我就不再把高考放在眼里。我开始钻研越来越难的题目，进行越来越离谱的实验。我想，清华里面应该都是我这样的学生吧，我会有很多志同道合的朋友，不用再跟这群只会做题的呆子在一起了。<br>

<br>
　　可是我的行为总是受到老师的压制，他们要把我们变成考试的机器。他们告诉我，沉下心来做习题，考试才能有把握。妈妈也帮着老师劝导我。看，一班的某某某这次模拟考试数学成绩比你高，多努力一下吧。我哪里听得进去，我才不在乎这点分数，我能解决更难的问题，老师都没法解决的问题。我开始有了逆反心理，开始早上懒床，装病请假不去上课。班主任，校长多次找我谈话，说我要沉下心来准备考试云云。但是我根本就听不进去，我鄙视高考，觉得他们没有资格出题来考我。然后我就有了心理疾病，大概是强迫症。高考语文的时候我居然怀疑监考老师认为自己在作弊，接着好像真的怕被抓住了一样，手发抖，头冒汗。然后我又想要是考不好，以前的优秀会不会也被人怀疑？他们会不会以为我以前的成绩全都是作弊得来的？手就抖得更厉害了。这时候，监考老师可能发现了我的情况，真的走了过来，站在我身后。害得我好几分钟不敢写一个字，因为手已经完全不听使唤。不过他还是走开了，这可怕的高考终于结束了。<br>

<br>
　　我们是考试前填的志愿，我根本不考虑其他学校就只填了清华。后来妈妈研究了一下，帮我添了一个天津大学在第二志愿。以下的志愿全部空白。大家觉得我真够大胆，可是我的心理状态让我发挥完全失常，比清华的最低分数线还差两分。特别是语文，才96分。天津大学第一志愿收满不要我。昔日的好学生，居然到了落榜的下场。我真的那么好吗？我问自己。我太骄傲，才落到如此地步吧。我开始怀疑自己是否应该那样瞧不起高考。看着爸爸的愁眉苦脸，妈妈的唠唠叨叨，真是生不如死。复读吗？那会是噩梦的继续。我不能再在这个学校待下去。再面对题海，我的心理疾病会让我自杀的。碰巧四川大学来招收高分落榜的学生，还给了我随便选择专业的机会。妈妈说，计算机现在很火热，出来好找工作。我虽然对工作不感兴趣，但是我比较喜欢写程序，于是就进了川大计算机系。<br>

<br>
　　两度退学失败<br>
<br>
　　不能不说进川大是个没有选择中的好选择。大学生活自由一些，我至少不会走上自杀的道路。可是我的毛病仍然在继续，我永远不满足学校里能学到的那么点东西。老师基本是照本宣科，我逐渐不再满足这种知识灌输式的教育。我觉得完全没必要上这个大学。<br>

<br>
　　川大的环境我实在无法忍受。军训的时候受够了同学和教官的委屈，我就想退学。我们的军训是在一个戒备森严的炮兵基地里，心里的苦向谁说啊！有一天我们正在路上齐步走的时候，我忽然看到一个女人挽着一个军官走了过来。那个军官的老婆怎么长的这么像我妈妈！要是妈妈来到我身边该多好！没想到回到营地，团长（原来是连长，我们来军训他就升一级做团长了）说有人来探访。我走过去，居然发现是妈妈！因为听说我想退学，她急忙向学校打听了军训的地点，几经周折跑过来，是那个军官带着她混进来的。我想我妈妈要是转行当间谍一定是个好料子。她说已经帮我办了退学，学校同意了，回去好好复习，准备考上清华......<br>

<br>
　　"好好复习，好好复习"......我的脑海里又浮现出高三的情景，这次我要跟一群更没用的复读的人在一起。脑子一阵疼痛之后，我说："妈妈，我不想退学了。"<br>

<br>
　　可是军训回到学校，发现宿舍如此差劲，我又想退学。妈妈又来帮我办理手续，可是结果我还是由于懦弱反悔了。害得学校办事的老师都骂我："你这个人简直神经病！"<br>

<br>
　　对啊，我确实是有病，不过我的是精神病，不是神经病。我恨我的高中，我恨我的大学，我恨高考，我恨中国的教育！是你们让我生病的。可是妈妈，她为了我已经费尽了辛苦。我不能再这样周折下去。我自己在学校里好好努力，准备考上清华的研究生吧。<br>

<br>
　　学校住宿环境很差劲，又经过好多麻烦事，我终于决定在校外去租房子住。后来我开始玩滑板，它让我变得勇敢。我心里逐渐平静下来，可以用心看书了。大二以后，我的学习生活才逐渐进入正常，自信开始恢复。<br>

<br>
　　梦的复苏<br>
<br>
　　记得川大教Pascal语言的老师第一堂课就对我们说："我们学校就是落后啊。外面公司里都用C,
C++了，我们还在教Pascal。你们以后要出去工作恐怕还是得学学VC什么的。"<br>
<br>
　　于是有的同学开始抱起一本本像"XXX圣经"之类的书开始学习，上数学课也在看这些东西。我当时自愧不如啊。自己就是小学的时候玩过一下学习机，可以说没有任何计算机基础。辅导员也经常夸他们几个动手能力强，以后公司就需要这样的人。他们出口就是Bill
Gates, 世界首富云云。军训的时候听着他们说什么DOS,
温95，我就只有张着嘴崇拜的份了。才想起我高中计算机竞赛的时候一道有关DOS命令的题没有做出来，现在听他们说才知道原来DOS是个"操作系统"。那操作系统又是什么，他们说每个电脑上都必须有一个操作系统......我真是愧不如人
-_-!<br>
<br>
　　正在我决定鼓起勇气后来跟上，准备拿起一本DOS大全从头啃起的时候，一次偶然的机会我接触到了Linux。后来又因为The Art
of Computer
Programming，接触到了Knuth。我才发现，课堂上讲的那些东西原来如此低级，有些东西学了就过时，学它干吗？我并不比别人落后多少。我一再的思考，什么是计算机科学？是什么让我们计算机系的人不同于其他系的。我有时候认为有了答案，但是后来答案又被我自己推翻。在思想的混乱中，我发现我逐渐摆脱了旁人的标准。我不再想像别人那样去考计算机等级考试，对微软的认证也不屑一顾。我自己学会了Linux，还会很多种当时别人听都没听说过的计算机语言。我学会了LaTeX，还因为找出Knuth书里的错误得到两张支票。上课要不就逃掉，背地里拿着大部头的"龙书"之类的原版英语书啃。要不就看我打印出来的GNU的一些资料，完
全不听老师讲。期末划重点的时候也不去，考试却总能考个八九十分，总有几个女生排名在我上面。不过我不在乎这点分数，考试和分数不再能评价我。同学们大概都觉得我是一个怪人，后来毕业了我才听他们说，他们管我叫"怪才"。我如此努力的学习着，对别的事情充耳不闻。我只有一个目的，就是毕业就离开这个鬼地方，进入清华大学上研究生。虽然大家不理解我在干什么，清华的老师应该挺在乎我学的东西吧。<br>

<br>
　　可是我没有想到，在我死啃书本的时候，我的创造力正在离我远去。在我盲目接受我认为高深的材料的时候，我失去了自己的创造。我成了比别人稍微好一点的技术工人，不再跟爱迪生和牛顿是一类人了。我高中的时候拼命想保存的创造力已经在苦读之下消失殆尽。我看书的方式变得顺序化，总想从头看到尾。我的高中老师们的目的，中国教育的目的，终于快达到了。<br>

<br>
　　清华，我来了<br>
<br>
　　大三的暑假，我来到清华想拿一些考研的资料。这是我梦中的地方呀，美丽的校园，比川大要大上好多倍吧，脚都走痛了才走到招待所。去系办，一个办事员态度很不好的给我一份资料。哎，学校好，人脾气就该大啊。忍了吧，要是真能考进来就好了。<br>

<br>
　　后来听一个老师说清华有一种学生叫"直博"，可以硕博连读，五年拿到博士学位。只要面试通过就可以进来学习。我心想这种方式好啊，我平生最讨厌的就是考试了。出高考题的那帮人，他们有什么资格考我！考研资料也是遍地飞。写了几本复习材料就自称什么"一代名师"，我最看不起这种人了，就会赚钱。我如果可以获得"直博"的名额，就可以永远摆脱他们了。想一想，要是硕士三年，博士三年，就要六年。现在五年就可以拿到博士学位，还不用考试，真是太好了。可是我又有什么资格获得清华的直博？我在川大从来没听说过这种东西。<br>

<br>
　　于是我就开始打电话联系老师，跟他们谈谈。面对他们的眉头，面对他们的笑脸却无可奈何的说"没有名额"，我都感觉没什么希望了。一个院士甚至对我说："你们四川大学是什么学校？二流都算不上，最多算个三流大学。你怎么能来我这里！"<br>

<br>
　　我深受打击，可是我还是没有放弃。最后我找到了一个老师，我们一开始就谈的挺投机。他听说我跟Knuth有联系，挺高兴的说，哦我知道他，好多年前来我们这里做过报告呢。我终于觉得找到了知音，于是决定就跟着他学习。老师找好了之后还有一个面试，是别的老师参加的，我说什么他们似乎没有认真听，就一个劲看我的考试成绩这种我不屑一顾的东西。我面试时特意穿上了Knuth送我的MMIX
T-shirt，他们大概根本不知道是什么，我也没有提起。<br>
<br>
　　不过老师只对我的体育成绩提出了疑问，说你怎么才80多分？你的身体能不能胜任繁重的学习任务啊？我笑着回答，我每天还跑5000米呢，我们学校打分比较严，难道清华的学生体育都考90？面试就这样通过了。<br>

<br>
　　推荐信与散伙饭<br>
<br>
　　面试通过后回到学校还要办一些手续。成绩单，推荐信等等，跟申请外国大学研究生院差不多，让我感觉挺正规的。院长对我挺好的，同意帮我签推荐信。可是签完字之后他对我说："你别以为他们觉得你是个人才。他们是根本招不到人！他们那里像你这样的学生都出国了，剩下的是最差的。谁想读博士啊？你别太高兴了。"<br>

<br>
　　我笑着应付这突如其来的打击，在心里却不断为自己的选择辩护。清华一定是好样的，不会让我失望。它是我的梦啊。<br>
<br>
　　很多麻烦的手续之后，终于拿到了我梦想的大学的录取通知书，可以离开川大这个鬼地方了。毕业的散伙饭上，看着大家喝得酩酊大醉，还有人在咆哮说居然连川大的文凭都没拿到，我一个人默默地想象着即将到来的清华的快乐生活，暗自庆幸。<br>

<br>
　　散伙饭到了尾声的时候，我诧异的看到一个平时不太熟悉的同学拿着一杯啤酒走过来。我挺紧张，我最不喜欢别人给我敬酒了，说是客气，其实很虚伪。没想到他说："我敬你一杯，大牛人。听说你被清华大学录取作了博士。我干了，你随意。"<br>

<br>
　　我不知如何回答，我一向不知如何应付别人的恭维。还好他没有让我也干杯，倒是够尊重人。没想到喝完他接着说："我知道你是怎样的人。我很仰慕你，你是真正喜欢研究的人。可是我要告诉你，清华的人并不会比我们好多少。大部分人也只是想混一个学位，将来找个好工作。没有多少人可以跟你一起研究的，你去了必定很孤独。我就很奇怪你这样的人怎么不出国呢！你会后悔的。"<br>

<br>
　　我有点不高兴了。一个人说你的选择是错误的，你的反应是什么呢？反正我当时为我的"清华梦"作了一番辩护，说我进去自己好好研究，应该还是能够很好的，毕竟这是我从小的梦啊。可是没想到，他说的居然是对的，我现在开始感谢他了。<br>

<br>
　　计算几何，创造力的复苏<br>
<br>
　　清华还是一样的上课方式，大部分课也是很多人一起上，一起打瞌睡。老师也是照本宣科，我居然发现他们其实跟川大的老师没什么区别。清华的不同之处就是，一到考试的时候原来进行的一切娱乐活动都不见了人影。原本每天晚上都有人一起玩轮滑，考试的时候就只剩下我孤零零的一个人。因为大家都怕考试，开始熬夜复习了。还有就是上课不容易逃课了，有些老师会突然点名，缺席会严重影响最后的成绩。<br>

<br>
　　对于博士生，传说还有一个规定，那就是后10%淘汰。也就是说，不管你成绩如何，如果成绩排名在课程的后10%，那么就要重修。而如果两门功课重修，就会被开除。面对如此残酷的规定，很多同学都惶惶不可终日。我就是在隔壁同学的唠叨声中度过了第一期。不过我还是没有把考试当回事，所以我也没有去验证这个说法的官方真实性。我仍然不去听老师划重点，我仍然不觉得老师出的题目有什么好，我仍然讨厌有人让我们用手算矩阵。可能觉得太残酷，还是觉得要是开除了博士生谁来干活，这条规定后来改成了如果博士生上了80分就可以不重修。我也不知道为什么我觉得考砸的科目也上的了80，故意放我过去的吗？<br>

<br>
　　但是我的生命中出现了这样一门课程。它改变了我对老师的看法，让我觉得上课原来也可以如此有趣。这就是计算几何。上课的人很少，只有十来个人。因为听说这门课很难，很多同学都没有选。但是我就是那种知难而进的人。老师上课的方式跟别的课程很不一样，大家坐在一个小教室里，老师有精美的幻灯片，有动画，不时还插入一段大科学家，大哲学家的名言。上课时老师会停下来很多次让学生提问题，下课大家都积极踊跃的讨论新奇的问题。课程的评分方法也很特别，平时成绩占到30%的分量，作业分为几种分值，可以自己选择做不做，作业的总分数乘以30%，加上最后大作业的分数乘以70%，就是最后的得分。说真的，这门课太有趣了，我就只逃过一次课。但是还是有时候人数不到一半，因为其他课程压力太大，有人都去复习别的课程了。但是邓老师从来不点名，还对逃课的同学表示同情。还问我们在座的有没有其他课特别紧张的，下次课可以不来。真是让人感动。<br>

<br>
　　我就是在这门课上认识了王益，我们亲密无间的合作，让我领略到了什么叫做研究。大作业的时候我们在一个小组，其实是三人一组，但是那第三个人其实什么也没干。我和王益决定写一个3D的Voronoi图扫描算法演示程序。王益的3D图形编程能力很强，所以他做界面，由我负责算法生成数据作为后端。我们分别在自己的机器上编写程序，不时的打电话讨论接口的设计问题。我找到了Bell
labs 的 Steven Fortune 的算法程序，决定看懂它，然后改造成演示需要的分部运行的算法。但是 Fortune
的程序几乎没有注释，而且使用了一种奇怪的数据结构，很难理解。Fortune
还在程序里说到，这个算法虽然有效，但是对于程序员来说是一个挑战。所以我email请他给我一份算法论文的拷贝，他同意了。但是一个月之后，信才到我手里，那时我们已经完成了作业。因为我花了一个星期看懂了他的程序，还换掉了他的麻烦又低效的数据结构。随后成功的把后端与王益的前端设计好接口联合。等我看到
Fortune
的论文，发现程序里面其实已经改进了论文的核心内容。我深深体会到实践的重要性，也许有了他的论文我反而会被误导，写不出实际可以运行的程序。<br>

<br>
　　由于我们的团结努力，老师对我们的大作业非常满意，他给了我们最高的分数
100。由于我们两个都在课下超额完成作业，所以总的分数我们两个都是满分。这是我阔别已久的100分。只有在小学我才拿到过这种分数啊！对于一个对考试成绩满不在乎的人，100
又意味着什么？如果是别的课程我会毫不在乎，就像我得了80分一样。可是这个100分是我们团结研究而来的，它包含了对我们的合作意识，对我们的友谊，对我们的热情的肯定。虽然我觉得我们的东西还有改进的余地，但是我接受这个100分！也只有这样的课程，我才可能得100分。<br>

<br>
　　从此我感觉到了什么叫做研究。这跟我小时候干的那些事情没有什么两样。你在身边发现一个问题，想知道为什么。然后你就想去获得解决这个问题的知识。你去看书，你去问专家，你上网去搜索。如果没有发现答案，那么好啦，你就可以自己试图去发现为什么，这是最有趣的部分。知道了为什么，就想让这个东西有用处，对人们的生活产生好处。这就是研究。<br>

<br>
　　《完全用Linux工作》与TeX的推广<br>
<br>
　　这么说来我还是对清华有些好感。遇到一个好老师让我从呆头呆脑的技术工人的状态恢复过来，开始追求自己的梦想。可是第一年把所有的课程上完之后，我就发现原来清华所谓的"研究"是如此混沌。其实清华大部分人进行的所谓的"研究"是什么呢？其实就是写作，不是科学研究。这一点以后我会详细叙述。<br>

<br>
　　远远看去外观华丽的有着先进的工作站的实验室，却没有可以安心看书的地方。机器挨着机器人挨着人，书都没地方放。师兄师姐们都在忙着用word写论文，不时有两个人隔着几行机器大声谈话。实验室通风不好，还有一个大型工作站在嗡嗡作响，我进去一会儿就觉得头晕，所以后来就不想去了。PC机以前都是公用的，每次都会用不同的机器，却没有我想用的软件，麻烦死了。好不容易实验室买了新机器分配给个人，装上一个
Linux
系统开始写程序，还在Sun工作站上安装了多达1G的GNU程序。却被一个师兄嘲笑说那种跟DOS一样落后的东西你居然也用。于是我写了一篇文章叫做《完全用Linux工作》，放在主页上驳斥这种观点，引起网上linux界轩然大波。后来我又发现几乎全校的论文都是word排版的，我本科毕业论文就用LaTeX了，清华居然这么土！我对word排版的论文质量恨之入骨，所以又写了文章宣传
TeX，打击 word
在论文排版的市场。这下子我出名了，真没想到，出名不是因为我的研究成果，而是因为这些业余的东西。我起初其实不希望我因此出名，但是看到旁边的人都用上了
TeX，我觉得我还是做了一件好事，至少让论文看起来漂亮了一些。<br>
<br>
　　可是论文的内容，却是我永远的痛！<br>
<br>
　　培养计划<br>
<br>
　　我在第一年就把功课全部上完了。本来我想多选几门课，比如法语，可是清华的博士要选课需要提交一个"培养计划"给导师签字。导师同意之后才能修改。导师看到我选了法语，就说这个第二外语还是自己学学就行了吧，旁听也行啊，我主要是怕你课太多了考试不通过就麻烦了。我当时没有说什么，就把法语去掉了，只留下刚够学分的课程。其实我还想选很多的，体育，音乐什么的，都不好意思跟导师说。后来才知道宿舍对门的硕士生选了钢琴课他们导师都不管。为什么我们就受到如此待遇？<br>

<br>
　　可是没有把法语加到培养计划却成了我的遗憾。有一个新学期我去旁听了第一节法语课之后老师就说，我知道很多同学是来旁听的，这样教室里人太多了，效果不好。这对自己对大家都不好，下次请旁听的同学不要来了。我脸皮薄，下次就没有去了。后来自己想自学却又没有老师教，看了十集Reflet之后就此作罢。<br>

<br>
　　后来我终于明白了，清华不需要全面发展的博士生，而其实导师还会在某种程度上削弱学生的能力。导师并不是真的为我们好，而是不喜欢我们上课，因为上课不但会花掉研究（或者干活）的时间，而且让他们眼界太开阔，这样学生会很容易有别的选择而走掉。所有的活动：助教，实习，都必须有导师签字。而大部分导师就会找借口不让学生干这些事情。不给他们助教和实习的机会，让他们以后不好找工作，只能为自己服务，或者为自己的熟人服务。甚至这次我去西藏，要办边境证都要有导师签字。办事的老师说，没有导师签字，你跑出去了不回来怎么办？大妈，我跑那种鬼地方干吗？<br>

<br>
　　除了这些，还有两大法宝就是博士学位和违约金。清华的博士学位有多值钱知道吗？不知道？那么博士退学要交30000块钱的违约金，这下大部分穷苦学生怕了吧。这就是你们的卖身契。清华就是这样把研究生牢牢地控制在自己的掌握之下。我对一个如此害怕学生跑掉的不自信的学校还能说些什么？如果你是好样的，就不会害怕我们跑掉！该跑掉的最后终究会跑掉。<br>

<br>
　　我的自我培养<br>
<br>
　　在学习上，我永远是个吃不饱的人。选不了课，我就去旁听。旁听后觉得老师讲的不好，我就自学。在我有空的时候，我就会去图书馆借书看。在我本科的时候，我就已经发现自己的一个特点，我会很快发现新的东西，并且学会使用它。虽然这些东西并不是创新，但是它们丰富了我的技能，让我有更大的能力去进行创新。<br>

<br>
　　计算几何课的一次作业，我为了写一个算法的演示程序，花了3天时间学了一点Java语言，正好能够完成那个程序。我开始接触到TeX的底层细节，看完了The
TeXbook，并且找出一道练习题答案的错误。开始移植gbkfonts程序，作为我的CWEB语言的练习。看完了几乎所有 Xlib
的手册，深入了解了 XWindow 的工作原理。我接触到 Scheme，并且做完了 SICP 的大部分习题。我领会到 LISP
的强大，改变了我们多年以来对这种古老语言的误解。接着我又学会了 Common
LISP，并且开始用它设计用来研究计算几何的一个函数库。另外还找了一些希奇古怪的程序来玩，写了一些心得体会放在网上给别人看。<br>
<br>
　　我意识到自己数学还不够强，就开始看一些数学方面的书。Concrete Mathemtatics, What is
Mathematics?, Science and Hypothesis, GEB, ...
虽然每一本都没有看完，但是我逐渐相信自己的数学能力，发现数学原来如此简单。我开始对哲学感兴趣......<br>
<br>
　　我们也有讨论，原来是这个样子<br>
<br>
　　上完课，就该开始搞研究啦。可是研究什么呢？老师给我几篇论文看，意思是让我看看有没有什么想法。<br>
<br>
　　我开始感觉没有头绪，就跟导师说能不能找师兄师姐跟我讨论讨论，还有别的人在做这个吗？他说，就你一个人做这个，每个人做一个题目，独立思考，这就是研究。我觉得是啊，我应该独立思考。可是过了一段时间发现不行啊，我想实现一个想法，但是我不知道是不是已经有人试过失败了。实验的时间开销会比较多，所以我想知道那么多厉害的人，为什么都不用这种明摆在那的方法？当我再次提出需要讨论的时候，他似乎有点生气的说："你为什么总是想有人跟你做一样的东西啊？你不是想抄袭别人的论文吧？"<br>

<br>
　　我不发话了。继续做我的实验，结果确实不理想。虽然自己实践很重要，可是要是能利用别人的经验，何乐而不为呢？这并不是偷懒。如果有人讨论，很多时候一个人提出一个问题，另外的人就会告诉他这个问题是不是有人做过，有什么重要性，凭直觉告诉他有什么难度。可是如果没有讨论，连问问"有没有人做过"的机会都没有！<br>

<br>
　　后来我就经常上网看看国外的大学怎么搞研究，发现他们都有 seminar，讨论组。后来又买了一本 A Beautiful
Mind，看到Princeton以前的天才们每天都在一个地方喝茶，讨论问题，争得面红耳赤，回家分头思考，做实验，第二天喝茶时再讨论。那就是我从小梦寐以求的生活啊！计算几何课已经让我爱上了与人合作和讨论的方式，现在却孤零零一个人了。我必须告诉导师，合作和讨论是非常重要的。在我据理陈述之后，他说："好吧。反正师兄师姐各自有自己的事，你要讨论什么就跟我和你副导师讨论吧。"<br>

<br>
　　于是我就开始了跟他们两个星期一次的见面讨论。每次讨论都感觉他们不知道我在说什么，他们心里想的都只是这个能比别人的好多少呢？能不能投到这个会议呢？如此宏观。我觉得跟他们讨论完全是浪费时间。<br>

<br>
　　后来课题逐渐有了新的同学加入，导师决定跟中科院数学所的人一起申请一个项目来研究。于是我们两个星期一次去中科院讨论。不过感觉他们那边也差不多。中科院的老师觉得他们的研究太理论，期望我们能给他们带去一点实际的东西。可是我们也没有什么实际的东西，所有的问题都是从别人的paper里看到的。副导师就开始跟他们说这个问题有多么多么重要......<br>

<br>
　　他们也借此机会开始研究以前放下的一些问题。总之讨论的感觉就是没有目的，没有主题。有时有人说他在想一个什么问题，说了一会儿就被否决了。有时候就是一个人看了一篇paper之后做一个感想。我坐在那里就在想，我们到底在干什么？我们甚至都不知道什么东西值得研究，还研究什么？后来师弟师妹们就开始考虑把问题变一变，看看能不能产生新的问题。他们的做法照我的话说就是"有问题也要解决；没有问题，制造问题也要解决！"<br>

<br>
　　博士生论坛的时候，同学们都觉得有类似的问题，讨论不足，交流不足。所以我提议成立一个类似国外大学的 Common
Room，用来讨论问题。可是大部分老师说："这样一个房间，天天都要有那么多人在里面待着。谁来出这个钱？"是啊，老师自己的办公室都要钱，哪里可能有什么
Common Room？就算有了 Common
Room，在里面讨论的无非还是文章发到哪里的问题。制度决定了行为，我的设想太理想化了。<br>
<br>
　　分析一下，为什么老师不提倡讨论呢？因为问题是有限的。老师辛辛苦苦这么多年搞来搞去都在搞这些问题，分配给你们每人一个，互不冲突。要是两个人都搞一个问题，这下好了。出了成果论文归谁？学校要求必须第一作者才算论文数。要是两个人都写论文，那么投到同一个会议肯定有一个要被reject。这样对集体发展不利嘛，大家不就是发几篇论文混毕业吗？何苦？<br>

<br>
　　paper, paper, 还是paper<br>
<br>
　　但是我更关心的是论文的内容。说到论文我就痛心。我的方向上我至今还没有看到几篇我觉得像样的文章。我主要进行集成电路布线算法的研究。看起来高深，其实是很简单的问题，一个平面上有一些点是电路里的电极，现在需要用铜线把它们连起来，怎么样让连线的长度或者时延最短？这个问题跟几何上一个有名的问题
Steiner tree 问题有关系。我的导师就是以前写了一篇这样的paper发到IEEE transactions。<br>
<br>
　　已经毕业的一个师兄就在他研究的基础上修改来修改去，发了好几篇paper。英文的不够还翻译成中文，投到国内的期刊。后来一个师姐又在这个师兄的基础上进行修改，又发了好多篇。可是在我看来，他们的论文纯粹就是炒冷饭，没有什么创新。一个问题解决了，那么解决问题的人显示了他们的聪明，至于这个问题对人有什么用，他可以暂时不管（虽然我也严重反对这种做法）。后来又有人来搞这个问题，多半是被老师分配来的。他也小修改一下，修改想法其实不费工夫，主要是你怎样把你的
Introduction 写好？可以让别人觉得你的工作有意义？这就是功夫。作家的功夫。我有一次面见INRIA的头目
Jean-Claude Paul 时，他就对我说："Tsinghua students are all writers, not
scientists."<br>
<br>
　　现在清华研究生做的事情无非就是，写好paper，然后找个地方投出去。SCI
的最好，EI的其次。偏僻的没人看的杂志也没关系，交钱也没关系。我就知道日本的一个SCI索引的期刊收1000美元的版面费。导师出钱，不投白不投，投了好毕业呵！<br>

<br>
　　现在我也被"分配"来做这个问题。虽然说是一个有名的问题，但是这个有名的问题已经被研究了好几十年了。有很多牛人做出了很重要的贡献，这里面不乏
D.Z.Du 之类的传奇人物。但是我们为什么研究这个问题？我至今没有搞懂。<br>
<br>
　　开头导师只是给了我两篇paper，据说是以前他一个得意门生写的，美国某大学的副教授。其中有一篇说是如何在不构造 Delaunay
triangulation的情况下生成 MST （最小生成树）。看到这篇文章开头说在 rectilinear metric下,
Delaunay triangulation 就不能用来构造 MST 了，所以他设计了一个新的算法。这个算法比起 Leo Guibas
的算法更加简单。文章里还提到一次 Matroid，让初出茅庐的我觉得高深莫测。可是我对"Delaunay triangulation
不能用来构造 RMST"这个说法产生了怀疑。经过理论分析我觉得即使在 rectilinear metric<br>
下，Delaunay triangulation 也可以用来构造 MST 的，我决定实践我的想法，写一个程序从Delaunay
triangulation 构造出一个 RMST。这本身不是什么创新的工作，可是我却在想，这样一个东西能不能用来构造 Steiner
tree 呢？后来我真的就想出一个办法。实验表明我的算法比以前的算法要快几倍。<br>
<br>
　　这是不是说我的算法是一个值得写paper的东西呢？导师说我应该写一篇，但是我认为我只是在挑别人的毛病时意外想出了一个改进的算法，并不会对将来的研究有什么改进。虽然程序快了一些，但是很少有那么大的线网需要这么快的算法，而且几倍的提高在我眼里不算是一个理论上的改进。所以我内心觉得这个结果不令我兴奋，不想写论文。但是在老师的一再要求下，我居然把这个研究写成了两篇paper。按照他的说法："应该分阶段总结你的成果。"<br>

<br>
　　起初投出去的时候评委总是说这个东西不实用，导师说这是评委的问题，他们觉得不实用我们就投到理论一点的会议。经过几次投稿，还是失败了。我终于忍不住了，对导师说出我的想法，我说："看一个作家的水平，是看他扔在垃圾筐里的纸。就让我把这篇paper永远藏在我的垃圾筐里吧。"<br>

<br>
　　但是他不甘心，说你要相信自己的实力，然后把我的算法胡乱夸奖了一番。我说我不管了，随便你怎么办。我就开始研究我自己喜欢的东西去了。之后他居然真的投中一个欧洲的会议，还是被
LNCS 收录的，LNCS 是 SCI 索引的，所以我居然有了一篇 SCI 文章！我自己不喜欢的文章也是 SCI 了！<br>
<br>
　　第二篇论文就更传奇了。几投不中，就其原因，评委说是没有和现在最先进的算法程序实验比较。而我没有比较的程序，就是那个让我鄙视的人的程序。没办法，求他给我代码，只给
binary，也不给源代码。比了一下，确实比他快。不过我估计他程序写的有毛病，老是 core
dump。不过还是记录下数据，添到论文上。一投就中，得了一个最佳论文奖。然后就有一篇校内新闻宣传："我校王垠同学获得XXX会议最佳论文奖。这是大陆学者首次在如此高级别的会议上获得如此高的奖项。"<br>

<br>
　　这个"高级别"的会议，在我看来就是个垃圾。美国人都把最差的论文投到这里，就是为了来旅游一圈而已。<br>
<br>
　　我见过的这种低级别的会议，低质量的论文几乎都是从 IEEE 那里出来的。道理很简单，IEEE
会议多，会议论文集都像两块砖头那么厚，还是双列小字排版，当然能容纳下这么多的垃圾了。所以我对 IEEE 也没有好感。<br>
<br>
　　火山小规模爆发<br>
<br>
　　第一篇投中了会议之后，副导师很高兴的说"代替我去开会"，到希腊Santorini岛玩了一圈。回来还跟我说希腊不好玩，好苦啊，幸好你没去。然后就继续要我为算法申请一个专利。<br>

<br>
　　写这个论文我都已经焦头烂额了，一点都不感兴趣。现在还要写专利，"要像教小学生做这件事一样，一步一步的把算法写清楚，举出实例"。我觉得快不行了，再这样折腾下去，我到博士毕业也许也就只搞出这些小儿科东西吧！我终于小规模爆发了一次。我坦荡的告诉了副导师我的想法，我觉得做学问应该是什么样，我觉得这么点东西不值得申请专利。我还告诉他我对国内的研究环境很失望。<br>

<br>
　　他慌了，可能以为我想要退学，赶忙找我谈谈。对我说，我知道你心中有很大抱负。所以这次就不写专利了。我知道你想有更好的研究环境，但是不踏踏实实做好现在的工作，又怎么能有大的创造呢？然后就开始举爱因斯坦，居里夫人的例子......
然后说，其实你在这里好好努力，将来出国的机会多的是，你想去Harvard也行，你想去Princeton，都行啊！<br>
<br>
　　你说行就行？你去去给我看看？我们实验室从来就没有去这些地方的。<br>
<br>
　　全面发展<br>
<br>
　　在对清华的研究完全失望了之后。我就准备考GRE，TOEFL出国了。我去上了一个新东方的班，没学到什么英语方面的东西，倒是接触了很多新的思想。老罗的言论特别有趣，虽然我不是完全赞同他的意见。写GRE作文特别培养思维能力。我为了写GRE作文，常常为了一个不明白的问题到图书馆翻阅英文的哲学书籍，有关教育的书籍......
对于很多问题我得到了完全不同的观点。大学的目的是什么？人的价值观是由理性决定的吗？等等等等。我读到了亚里士多德，柏拉图，康德等人的言论。甚至有个哲学家说
"All Animals Are Equal".
我看了他的文章觉得有很多可以批驳的观点。我看到迪卡尔的文章，说"要掌握科学就要掌握它的全部"，这句话真合我心意，我就是想做一个懂很多东西的人啊。我想结合艺术与科学。虽然我这个观点得到了某位图灵奖得主的批判，但是我仍然相信迪卡尔。<br>

<br>
　　从这些互相矛盾的观点中，我有了自己的判断力。我开始能够揭开从小蒙在我眼睛上的有色眼镜看问题。我开始检查我自己的思维，我以前的观点。看看它们是否是未经判断就盲目放进去的。我检查到很多很多的错误。我的待人接物，我对他人的理解上，都有不足之处。我还检查到妈妈传递给我的一些有色眼镜。我开始学会用自己新的方式对待他人，看待事物。我不再盲目相信权威，哪怕他是诺贝尔奖得主，图灵奖得主。我有了自己的自由思维。<br>

<br>
　　在那段时间，我感觉我的心智大门被开启了。我开始尝试从来没有做过的事情，以及从来不认为我能做好的事情。我一次又一次的相信我能。我能学会画画，我能打好太极拳，我能理解古典音乐......
世界还有那么多美好的事情等着我去学习去开发啊！<br>
<br>
　　可是，我们却像囚犯一样被判了5年在清华。博士学位就是我们的枷锁。<br>
<br>
　　醒悟，paper的奥秘<br>
<br>
　　清华研究生谈论的重点是什么？是
paper。吃饭的时候谈，喝茶的时候谈，睡觉的时候也谈。隔壁的同学在进校第一年就为paper惶惶不可终日，说："你知道吗，他们要求我们发SCI，怎么办呢？我几个师兄都是因为没有paper延期毕业的。"
这恰好就是那个为后10%淘汰惶惶不可终日的同学。他的老师是个院士，可是他在手下就干一些写word文档之类的杂活还忙得要命，根本没有时间思考问题。<br>

<br>
　　后来听说学校有规定，博士生必须发4篇paper才能毕业，其中必须有一篇是SCI索引，或者两篇EI索引。看上去冠冕堂皇的SCI,
EI，不就是跟 google
差不多的东西吗？被它索引了怎么样了？特别是对文章的篇数作要求，而对质量没有判断。我其实读了两年都还不知道学校是这样规定毕业标准的。当我知道的时候，已经有人告诉我SCI=Silly
Chinese Index。真是让人啼笑皆非。<br>
<br>
　　学校没有能力评价学生的水平，就拿文章数来衡量。这样的毕业标准造就的是怎样的学生，怎样的实验室呢？难道导师真的没有能力判断paper的好坏吗？有些是，但是有些不是。即使他知道你的论文没什么价值，也会叫你发表。我发现paper数量的背后，是某些人的如意算盘。想一想是怎么回事吧。国家看什么来拨款研究？看paper。看什么来评价一个学校的水平，也是paper。国家没有能力评价你的能力，当然只有看你有多少paper。所以有了paper就有了钱。只要你能写paper，培不培养你，你将来的发展，关我们什么相干？你写的paper别人能不能看懂，能不能转化成生产力，管我们什么相干？怪不得有的院士想尽办法也要多收学生，宁愿自己帮学生出学费也要他进来。因为学生就是财源。paper可以带来基金，可以在美国买小车洋房，没有基金就让学生干活吧。一个月几百块钱吊着一条命在那里为你拼命，谁叫他们想要那个博士学位呢！<br>

<br>
　　该清醒了，博士无产阶级！<br>
<br>
　　告别清华的博士学位<br>
<br>
　　现在我已经厌烦了国内所谓的"学术"。我准备放弃清华的博士学位，出国找个好老师，进行真正的研究。博士第4年了，做出这样的决定真是不容易。有人告诉我不要放弃，你知道有多少人正在羡慕你？你知道一个清华的博士学位有多么值钱吗？但是我不能这么沉默下去了！<br>

<br>
　　博士学位，累坏了多少年轻的中国人！我不再为它浪费我的青春。如果国外也找不到好的老师，我就找一个简单的工作，和我心爱的人一起生活。有人说这是浪费人才？在清华混沌的过日子才是浪费呢！当一个侍者至少也让我感到对社会有贡献，看着顾客满意，我会露出笑容。可是做一个博士却没有。我感觉自己是个没用的人。<br>

<br>
　　我已经完全看透了中国教育的失败。我高中的时候就受到它的伤害，这种伤害延续到现在。中国教育已经成为埋没人才的祸首。留在这个圈子里就是屈服，我不出声，大家都不出声，这个世界就会继续这样郁闷的运转下去。我今天要对这个系统大声地说一声"不！"<br>

<br>
　　我离开了。可是中国永远也不缺少为清华拼命的人！因为他们的妈妈会告诉他们，清华是全中国最好的学校。你要考上清华，为我们光宗耀祖......<br>

<br>
　　行动<br>
<br>
　　2005年9月22日下午3点，我在东主楼导师的办公室里跟导师和副导师再次重申了我的想法。包括以上的一切，和我退学的打算。导师经过一番举例爱因斯坦，居里夫人，叫我踏踏实实的说教无效之后，严厉的批评了我只顾自己，不顾及教研组为我付出的心血。然后说："要是你不能再为实验室作研究，我们就不能支持你了。前两个月实验室发的钱我收回，你如果决定可以马上写退学申请。我们实验室没有什么损失，我们有的是人干你的事情。不过我要警告你，你一旦退学，连学校的住宿都要被收回！"<br>

<br>
　　接着是副导师尖声的咆哮："是啊，你瞧不起我们。我们是没有你聪明，可是我们勤勤恳恳......你知道你得的那个best paper
award，我们付出了多少努力吗？你认为这么容易拿到吗？那是多少国外专家鉴定......"<br>
<br>
　　真像是一场闹剧，一场梦。他平息下来之后，我说了一声"再见"，然后默默地走出了办公室。<br>
<br>
　　你们要退学申请？这就是我的退学申请。<br>
<br>
　　尾声<br>
<br>
　　晚上收到副导师的email说："还有一件事需要向你说一下：你在学校学习期间所取得的成绩包含你的努力、导师的指导帮助、同学们的帮助，还有学校和国家的支持。你作为博士生学习阶段取得的成果属于教研组、学校和国家。正如同我们作为职务发明的专利属于学校一样。<br>

<br>
　　你在MST、SMT等方面取得了结果，它属于教研组、学校和国家。单位有责任进行合理的应用，为国家建设、国家荣誉服务。有责任进行进一步的整理丰富、向高水平的刊物投送。这里我们想说明一下上述的情况，同时，也告诉你一下：你若愿意将这些成果进行进一步的整理、我们已经给你提出了具体的修改意见，欢迎你按照进行修改。你若放弃，我们将进行具体的改进、投递。我们将尊重你的意见。谢谢。"<br>

<br>
　　最后还是没有忘了paper的剩余价值。进一步验证了我的判断，他们在乎我吗？不。他们只在乎paper。至于我流离失所，又有何相干？我不知道有多少无知的弟弟妹妹又会把他们的研究建立在我不屑一顾的paper之上。</p>

]]></description><guid>http://www.i170.com/Article/115179</guid><trackback:ping>http://www.i170.com/Article/115179/trackback</trackback:ping><comments>http://www.i170.com/Article/115179#comment</comments><wfw:commentRss>http://www.i170.com/Article/115179/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/115047</link><title><![CDATA[谈谈对类看法]]></title><author>killercat</author><category>C/C++</category><pubDate>Sun, 22 Feb 2009 18:34:27  +0800</pubDate><description><![CDATA[<p>在《The C++ Programming Language》中有一个令人回味的，关于类这个概念的定义：</p>
<p>The aim of the C++ class concept is to provide the programmer
with a tool for creating new types<br>
that can be used as conveniently as the built-in types.<br>
<font color="#FF0000"><strong>A type is a concrete representation
of a concept.</strong></font></p>
<p>一个类型是一个概念的具体表述。这不意味着一个概念需要用一个类才能表示。</p>
<p>实际上，我们通常还可以使用别的手段来描述一个概念，比如说，我们使用两个变量 x, y 来表示点的概念。</p>
<p>但是，不得不承认的是，类通常是一种友好的用于表述某个概念的工具。现在看一个例子：</p>
<p>class Car</p>
<p>{</p>
<p>public:</p>
<p>&nbsp;&nbsp;&nbsp; void Run(int x, int y); // 这是一部在陆地上行走的车</p>
<p>};</p>
<p>注意，我们使用了两个变量来表示“点”的概念。</p>
<p>忽然有一天，我们的所有的车能够在天上飞了，不存在那么只能走在陆地上的车了，结果导致程序员不得不去修改接口：</p>
<p>class Car</p>
<p>{</p>
<p>public:</p>
<p>&nbsp;&nbsp;&nbsp; void Run(int x, int y, int z); // 从 2D 转向了
3D</p>
<p>};</p>
<p>可以想象，这接口的改动带来了不少的麻烦。假如当初我们使用类来表示“点”的概念：</p>
<p>class Car</p>
<p>{</p>
<p>public:</p>
<p>&nbsp;&nbsp;&nbsp; void Run(Pos target); // Pos 是一个表示点的概念的类</p>
<p>};</p>
<p>那么，如果车能飞上天，那么仅仅需要修改 Pos 类的实现（如果接口设计好的话），而不是 Car
类的接口了。程序员的负担相对较低了。</p>
<p>这里，我想表达的是这么一个观点：尽量用类来表达一个概念。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>

]]></description><guid>http://www.i170.com/Article/115047</guid><trackback:ping>http://www.i170.com/Article/115047/trackback</trackback:ping><comments>http://www.i170.com/Article/115047#comment</comments><wfw:commentRss>http://www.i170.com/Article/115047/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/114111</link><title><![CDATA[Socket API 概述（Mastering Complexity with ACE and Patterns 读书笔记）]]></title><author>killercat</author><category>C/C++</category><pubDate>Tue, 20 Jan 2009 01:35:36  +0800</pubDate><description><![CDATA[<p>Socket API 为 TCP / IP 协议簇提供了应用层接口。</p>

]]></description><guid>http://www.i170.com/Article/114111</guid><trackback:ping>http://www.i170.com/Article/114111/trackback</trackback:ping><comments>http://www.i170.com/Article/114111#comment</comments><wfw:commentRss>http://www.i170.com/Article/114111/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/113928</link><title><![CDATA[关于设计]]></title><author>killercat</author><category>Architecture</category><pubDate>Sun, 11 Jan 2009 16:17:41  +0800</pubDate><description><![CDATA[<p>设计是一项把需求转换为编码方案的活动。设计在软件开发中是必定存在的，无论何种情况下，我们都需要把需求转化为编码方案。<br>
设计是一个不断完善的过程，设计的缺陷可能在设计之初无法被发现，直到设计完成时才被察觉到，这导致了再次设计的需要。注意，我们在首次设计时应该尽可能的避免缺陷的出现，而不是视而不见以求下次解决。<br>

设计上的付出是必要的，在设计阶段发现错误并改正比编码后发现相同错误并改正的代价低的多，如果设计的错误拖延到维护阶段，那就更加不堪设想。<br>

设计存在优劣，必须明确这一点。敷衍的进行设计后果是很严重的（虽然偶尔也能更加快速的产生产品），糟糕设计的最大特点是无法响应需求变更。但也应该注意，优秀的设计有多种，糟糕的设计也有多种。<br>

&nbsp;<br>
事物的本质属性是一件事物必须具有的，如果不具有则就不在是该事物。事物的偶然属性是不起解决性作用的属性。例如，车总有轮子，没有了轮子就不在是车，那么轮子就是本质属性，但是轮子可能有
4 个，也可能有 3 个，无论多少个轮子依然是车，那轮子的数目就是偶然属性。<br>
本质复杂度源于需求，无论采取何种手段，何种技术都不会对本质复杂度造成任何影响，所以有人才会说，软件开发本身就很复杂（无论使用何种技术开发都是复杂的）。我们需要管理好偶然复杂度（偶然性的复杂度），例如，需求是开发一个可用的计算器程序（图形界面可有可无），这时，开发命令行的计算器就比开发
GUI 的计算器的偶然复杂度小，用 C++ 进行开发其偶然复杂度就比用 Dephi 高。敏捷开发和 Unix 中都强调
KISS，而敏捷开发更加强调应该使用简单的技术和工具，这都是为了避免偶然复杂度过高带来额外的成本开销。</p>
<p>
设计者应该真正理解偶然复杂度，如果设计出来的框架，在进行开发时需要开发人员关注于系统的每个细节，那么对于程序员来说偶然复杂度是高的，相比下，对于每个功能的开发，程序员只需要关心当前编写的任务，那么偶然复杂度是低的（COM
的设计非常强调的一点是封装，而不是复用）。</p>
<p>&nbsp;</p>
<p>设计的基本的原则：</p>
<p>1）尽量降低偶然复杂度。如果可以简单的解决问题，那为什么不这么做了？另外某些角度来说：</p>
<p>
模块化的系统（系统对“模块”一词有确切的定义），在一定程度上偶然复杂度较低，模块化的系统让程序员只需要关心当前开发的部分。</p>
<p>
2）尽量保持高内聚，低耦合。高耦合的系统惧怕变动（动一处而牵动全身），变动带来的问题通过关联进行传递。高耦合的系统的关键点在于：系统组成部分的关联过多，导致过多的相互影响，当关联数量到一定程度，整个系统就会很不稳定。</p>
<p>具体来说：</p>
<p>&lt;1&gt; 集成的困难：高耦合的各个程序组成部分需要花费较多时间进行集成。</p>
<p>&lt;2&gt;
测试的困难：一个部分的问题通过与其他部分关联传递到其他部分，那么意味着一个部分的变动可能导致整个系统的重新测试。</p>
<p>低耦合：在类这个层次上来说，除了底层的工具类（例如
STL）之外（工具类允许和系统中的大部分类发生关联），应该尽可能的减少类之间的关联。</p>
<p>3）可扩展。可扩展的一个标志是，无需改变系统底层，即可增加新的功能。</p>
<p>
4）可移植性。可移植性非常特别（似乎违背低偶然复杂度原则），它不同于软件的其他的特性，除非你保证你的项目永远无需移植到其他的环境中去，否则，你应该注意这点，因为通常来说，时间越长，越难移植，甚至最后只能重写，代价非常之高。</p>
<p>5）分层。分层的系统相对来说偶然复杂度较低，关联较少。每层都有每层的工作，相互影响较小。</p>
<p>&nbsp;</p>
<p>
另外，类的粒度也比较重要，大粒度的类间关联少，但是不可避免的就是类自身过于复杂。小粒度的类自身很简单，易于开发和维护，但是类间关联变多，通讯太频繁。粒度过大和过小都会带来较多的问题，应该根据经验作合理设计。</p>
<p>在 C++ 中使用巨大的类无异于使用 C 语言进行编程，这意味着你抛弃了 C++
强大的抽象能力。含有巨类的系统中的一个显著的标志是：含有大量重复代码或者相似代码（这归结于 C
语言不够强大的抽象能力和项目在时间上的压力）</p>
<p>&nbsp;</p>
<p>最后要说的一句是：KISS 和敏捷给太多人以误解，请仔细斟酌它们的含义（有几个人懂得 KISS
的真正含义）。设计是不可避免的，好的设计是至关重要的。好的设计在一定程度上控制了软件的成本，即使你的老板并不明白，但是你应该这么做。</p>
<p>&nbsp;</p>
<p>author: killercat</p>
<p>http://www.i170.com/killercat</p>
<p>&nbsp;</p>

]]></description><guid>http://www.i170.com/Article/113928</guid><trackback:ping>http://www.i170.com/Article/113928/trackback</trackback:ping><comments>http://www.i170.com/Article/113928#comment</comments><wfw:commentRss>http://www.i170.com/Article/113928/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/113798</link><title><![CDATA[OGRE 中的 Singleton]]></title><author>killercat</author><category>C/C++,Architecture</category><pubDate>Tue, 06 Jan 2009 02:36:31  +0800</pubDate><description><![CDATA[<p>OGRE 中的 Singleton 比较特别，所有的 Singleton 都继承于一个 Singleton 模板：</p>
<p>// Singleton 模板</p>
<p>template &lt;typename T&gt;<br>
class Singleton<br>
{<br>
public:<br>
&nbsp;&nbsp;&nbsp; Singleton()<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
assert(!ms_singleton);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ms_singleton =
static_cast&lt;T*&gt;(this);<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; ~Singleton()<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
assert(ms_singleton);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ms_singleton = 0;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; static T&amp; GetSingleton()<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
assert(ms_singleton);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return
*ms_singleton;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; static T* GetSingletonPtr()<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ms_singleton;<br>
&nbsp;&nbsp;&nbsp; }<br>
protected:<br>
&nbsp;&nbsp;&nbsp; static T* ms_singleton;<br>
};</p>
<p>// 使用模板（省略了原有的大量代码）</p>
<p>class _OgreExport LogManager : public
Singleton&lt;LogManager&gt;, public LogAlloc<br>
{<br>
public:</p>
<p>&nbsp;&nbsp;&nbsp; LogManager();<br>
&nbsp;&nbsp;&nbsp; ~LogManager();<br>
&nbsp;&nbsp;&nbsp; static LogManager* GetSingletonPtr(void);</p>
<p>&nbsp;&nbsp;&nbsp; static LogManager&amp;
GetSingleton(void);<br>
};</p>
<p>&nbsp;</p>
<p>OGRE 中使用引擎本身去调用构造函数的方式初始化 Singleton，而我们常见的 Singleton 都是第一次调用
GetSingleton 来创建实例，另外 Singleton 本身也不负责释放 ms_singleton。实际上，OGRE 的
Singleton 把对象生命周期的管理分离了出去，那么只要外部管理对象生命周期正常，那么使用 Singleton
永远不会出现问题，这样的设计使得 Singleton 更加容易使用在多线程的环境中，读者可以阅读 ACE 中 Singleton
的实现方式（n 种实现）。OGRE 的 Singleton 只是通过 Assert
通知用户已经存在实例，而没有禁止用户产生多个实例。</p>
<p>笔者对 OGRE 的 Singleton 稍微修改了一下：</p>
<p>#define SINGLETON_DECLARE(T) static T&amp; GetSingleton();
static T* GetSingletonPtr();<br>
#define SINGLETON_IMPLEMENT(T) template&lt;&gt; T*
Singleton&lt;T&gt;::ms_singleton = 0;\<br>
&nbsp;&nbsp;&nbsp; T* T::GetSingletonPtr() { assert(ms_singleton);
return ms_singleton; } \<br>
&nbsp;&nbsp;&nbsp; T&amp; T::GetSingleton() { assert(ms_singleton);
return *ms_singleton; }<br>
<br>
template &lt;typename T&gt;<br>
class Singleton<br>
{<br>
protected:<br>
&nbsp;&nbsp;&nbsp; Singleton()<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
assert(!ms_singleton);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ms_singleton =
static_cast&lt;T*&gt;(this);<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; ~Singleton()<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
assert(ms_singleton);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ms_singleton = 0;<br>
&nbsp;&nbsp;&nbsp; }<br>
protected:<br>
&nbsp;&nbsp;&nbsp; static T* ms_singleton;<br>
<br>
&nbsp;&nbsp;&nbsp; // Hide<br>
private:<br>
&nbsp;&nbsp;&nbsp; Singleton(const Singleton&amp;);<br>
&nbsp;&nbsp;&nbsp; void operator=(const Singleton&amp;);<br>
};</p>
<p>// 使用代码</p>
<p>class MyMgr : public Singleton&lt;MyMgr&gt;<br>
{<br>
public:<br>
&nbsp;&nbsp;&nbsp; SINGLETON_DECLARE(MyMgr)<br>
&nbsp;&nbsp;&nbsp; void SayHello();<br>
};<br>
<br>
SINGLETON_IMPLEMENT(MyMgr)<br>
<br>
void MyMgr::SayHello()<br>
{<br>
&nbsp;&nbsp;&nbsp; cout &lt;&lt; "Hello world!" &lt;&lt; endl;<br>
}</p>

]]></description><guid>http://www.i170.com/Article/113798</guid><trackback:ping>http://www.i170.com/Article/113798/trackback</trackback:ping><comments>http://www.i170.com/Article/113798#comment</comments><wfw:commentRss>http://www.i170.com/Article/113798/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/113724</link><title><![CDATA[C++ 命名规范]]></title><author>killercat</author><category>C/C++</category><pubDate>Thu, 01 Jan 2009 17:12:55  +0800</pubDate><description><![CDATA[<p>在一个项目中，命名风格保持一致，否则会降低源码的可读性。</p>
<p>&nbsp;</p>
<p>命名必须要注意的两点：</p>
<p>1）永远不要使用晦涩的名字</p>
<p>2）总是使用全大写字母表示宏和常量</p>
<p>&nbsp;</p>
<p>匈牙利命名法：</p>
<p>匈牙利命名法的一个特点是将类型信息混入名称中，例如：</p>
<p>int nNum = 0; // n 为类型信息，表明 nNum 是一个 int 类型</p>
<p>class CUser; // C 为类型信息，表明 CUser 是一个类</p>
<p>
通常的观点认为，在名称中加入类型信息会增加代码的可读性，实际上，这种效果甚微。加入类型信息的不良表现之一是降低可维护性，一个很简单的例子：</p>
<p>class CUser</p>
<p>{</p>
<p>private:</p>
<p>&nbsp;&nbsp;&nbsp; int m_nID;</p>
<p>}</p>
<p>如果出现某种情况导致需要修改 m_nID 的类型为 long，那么 m_nID 应该改名字为
m_lID，那么意味着要在整个类中修改 m_nID。更糟糕的情况是：</p>
<p>class CHome</p>
<p>{</p>
<p>public:</p>
<p>&nbsp;&nbsp;&nbsp; void f();</p>
<p>}</p>
<p>void CHome::f()</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp; int nID = m_pUser-&gt;GetID(); // nID 需要改成
lID</p>
<p>&nbsp;&nbsp; // 下面大量使用 nID</p>
<p>}</p>
<p>可见，CHome 中的 f 函数的局部变量 nID 在 id 类型由 int 变成 long 时也受到了影响。</p>
<p>
总的来说是将类型信息引入名称中致使维护成本增加，我们本无需因为类型的改变维护名称，匈牙利命名法将类型绑定在名称上，使得必须在类型变动时维护名称。</p>
<p>在泛型编程中，几乎无法使用匈牙利命名法，因为具体的类型信息并不存在。</p>
<p>除非你使用纯文本编辑器，否则名称中加入类型信息的做法不会为你增加任何可读性（现代的 IDE
甚至是一些高级文本编辑器，在你用鼠标点击到变量名称上时，就能显示变量的类型），它已经过时了。</p>
<p>&nbsp;</p>
<p>一套可行的命名规范：</p>
<p>1）类名、枚举名、结构名、联合名、typedef 定义的类型名、函数名可以使用 LikeThis 的命名方式。</p>
<p>2）变量名使用诸如 likeThis 的命名方式（首字母小写）</p>
<p>3）类成员变量名前加 m_ 例如：</p>
<p>class User</p>
<p>{</p>
<p>&nbsp;&nbsp;&nbsp; int m_id;</p>
<p>}</p>
<p>全局变量前加 g_ 例如：</p>
<p>int g_id;</p>
<p>静态变量使用 s_ 例如：</p>
<p>static int s_id;</p>
<p>这里说明一下，为什么需要把作用域和链接性信息融入名称中：</p>
<p>&lt;1&gt;变量作用域和链接性改变的情况是很少的，例如，很少的情况下会把一个成员变量改成静态变量</p>
<p>&lt;2&gt;编程中使用的工具常常不会直观的显示变量的作用域和链接性</p>
<p>&lt;3&gt;在许多高质量的代码中，均不同程度的将作用域信息融入变量名称中（通常使用 "_" 来表明其作用域）</p>
<p>对于静态类成员变量，通常使用如下方式表示：</p>
<p>template &lt;typename T&gt;</p>
<p>class Singleton</p>
<p>{</p>
<p>protected:</p>
<p>&nbsp;&nbsp;&nbsp; static T* ms_instance; // 作用域前于链接性</p>
<p>}</p>
<p>4）宏和常量使用 LIKE_THIS 的命名方式</p>
<p>5）namespace 使用小写字母命名</p>
<p>6）接口使用 ILikeThis 的命名方式</p>

]]></description><guid>http://www.i170.com/Article/113724</guid><trackback:ping>http://www.i170.com/Article/113724/trackback</trackback:ping><comments>http://www.i170.com/Article/113724#comment</comments><wfw:commentRss>http://www.i170.com/Article/113724/commentRss</wfw:commentRss></item> </channel></rss>
