﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-xosen-文章分类-C++通用编程</title><link>http://www.cppblog.com/xosen/category/10099.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 19 Apr 2009 21:42:11 GMT</lastBuildDate><pubDate>Sun, 19 Apr 2009 21:42:11 GMT</pubDate><ttl>60</ttl><item><title>C＋＋中更好地使用Singleton(单件)模式</title><link>http://www.cppblog.com/xosen/articles/78909.html</link><dc:creator>xosen</dc:creator><author>xosen</author><pubDate>Fri, 03 Apr 2009 18:18:00 GMT</pubDate><guid>http://www.cppblog.com/xosen/articles/78909.html</guid><wfw:comment>http://www.cppblog.com/xosen/comments/78909.html</wfw:comment><comments>http://www.cppblog.com/xosen/articles/78909.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xosen/comments/commentRss/78909.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xosen/services/trackbacks/78909.html</trackback:ping><description><![CDATA[<h2>C＋＋中更好地使用Singleton(单件)模式</h2>
<input id=search-key type=hidden value=C＋＋中更好地使用Singleton(单件)模式 name=search-key>
<div class="rl entry-titlerl fenlei-Span">分类:<a href="http://erisenxu.bokee.com/cat.10227207.html"><font color=#03354f>设计模式</font></a></div>
<div class=fbzt><span class=f><span class=pub-date title=发布日期>2006.7.22</span> <span class=pub-time title=发布时间>17:50</span> <span class=ln-author>作者：<a class=author href="http://id.bokee.com/showInfo.b?username=erisenxu.bokee.com"><font color=#03354f>黑猫侦探</font></a></span> | <a class=author href="http://erisenxu.bokee.com/viewdiary.12125852.html#remark"><font color=#03354f>评论：0</font></a> | <span class=ln-viewed id=h12125852>阅读：776</span> </span></div>
<div class="entry-body nerr">
<p>所谓Singleton模式，其主要作用是保证在应用程序中，一个类Class只有一个实例存在。 在软件开发中，Singleton模式应该是使用比较广泛的一个模式了，例如，实现Log系统的类、全局配置的类，以及建立目录、数据库连接的类、全局统计的类等等，都可以使用Singleton模式来实现。因为通常这些类，只允许一个实例存在，而且该实例可以在其他任何对象、任何函数中都可以被调用。</p>
<p>在C＋＋中使用Singleton模式，要注意的问题，也是如何管理该对象所使用的内存了，呵呵！对内存的管理，真的是一个老生常谈的事情，可是又不得不考虑！是呀，Singleton对象的内存怎么释放呢？因为该对象通常是为系统中所有其他对象服务的，而C＋＋中又没有垃圾回收机制。正因为如此，很多人选择不释放其内存，因为通常Singleton对象的生命周期，会一直到应用程序运行结束，程序结束后，可以由操作系统来回收内存。当前，大多数的操作系统都可以完成这个工作，可这实在不是一个好习惯。</p>
<p>有没有更好的方法呢？当然有，那就是不要使用指针，即，不要象《设计模式》这本书里面叙述的那样实现Singleton，而是如下来实现：</p>
<p><font color=#0000ff>class</font> SingletonTest</p>
<p>{</p>
<p><font color=#0000ff>protected</font>:</p>
<p>&nbsp;&nbsp;&nbsp; SingletonTest() {}&nbsp;<font color=#008000>// 将构造函数保护起来</font></p>
<p>public</p>
<p>&nbsp;&nbsp;&nbsp; <font color=#0000ff>static</font> SingletonTest&amp; getInstance(); <font color=#008000>// 使用instance来创建对象</font></p>
<p>};</p>
<p>SingletonTest&amp; SingletonTest::getInstance()<br>{<br>&nbsp;&nbsp;&nbsp; <font color=#0000ff>static</font> SingletonTest&nbsp;instance; <font color=#008000>// 申明对象时，使用static</font><br>&nbsp;&nbsp;&nbsp; <font color=#0000ff>return</font> instance;<br>}</p>
<p>使用该对象的方法如下：</p>
<p>&nbsp;&nbsp;&nbsp; SingletonTest::getInstance().函数名;</p>
<p>或：</p>
<p>&nbsp;&nbsp;&nbsp; SingletonTest* test = &amp;SingletonTest::SingletonTest();</p>
<p>&nbsp;&nbsp;&nbsp; test-&gt;函数名</p>
<p>由于getInstance中，申明对象时使用了static，所以调用getInstance只会运行一次申明对象的那条语句，也就是，只会在系统中创建一个SingletonTest实例，又由于所创建的SingletonTest实例不是指针，在程序结束时，会将内存释放给操作系统。</p>
<p>&nbsp;</p>
</div>
<img src ="http://www.cppblog.com/xosen/aggbug/78909.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xosen/" target="_blank">xosen</a> 2009-04-04 02:18 <a href="http://www.cppblog.com/xosen/articles/78909.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC 之 Checked Iterator</title><link>http://www.cppblog.com/xosen/articles/78908.html</link><dc:creator>xosen</dc:creator><author>xosen</author><pubDate>Fri, 03 Apr 2009 18:15:00 GMT</pubDate><guid>http://www.cppblog.com/xosen/articles/78908.html</guid><wfw:comment>http://www.cppblog.com/xosen/comments/78908.html</wfw:comment><comments>http://www.cppblog.com/xosen/articles/78908.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xosen/comments/commentRss/78908.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xosen/services/trackbacks/78908.html</trackback:ping><description><![CDATA[VC 之 Checked Iterator<br>&nbsp;&nbsp;&nbsp; 作者：tyc611.cublog.cn，2008-08-27
<p>--------------------------------------------------------------------------------<br>&nbsp;&nbsp;&nbsp; Checked Iterator是指具有越界检查功能的迭代器，并且会在检查到越界操作时触发运行时错误处理（调用非法参数处理例程或者抛出异常）。VC从VS2005 开始支持Checked Iterator。另外，VC还支持Debug Iterator，有更多的检查功能，这里不予讨论。</p>
<p><br>--------------------------------------------------------------------------------<br>Part One 编译</p>
<p>&nbsp;&nbsp;&nbsp; Checked Iterator能够确保迭代器不会发生越界访问（如果发生越界访问，则会进行相应的处理）。如果在需要Checked Iterator的地方使用了非Checked Iterator，则在编译时会产生编译警告C4996（Level 3）。如果需要禁用此警告，可以通过定义宏_SCL_SECURE_NO_WARNINGS来达到目的。</p>
<p>#define _SCL_SECURE_NO_WARNING<br>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 可以通过定义宏_SECURE_SCL的值来启用/禁用Checked Iterator的检查功能。如果宏_SECURE_SCL被定义为1，则启用Checked Iterator的检查功能；如果宏_SECURE_SCL被定义为0，则禁用Checked Iterator的检查功能。如果Checked Iterator发现迭代器越界，则会触发运行时错误，该运行时错误的具体行为与宏_SECURE_SCL_THROWS的值相关。默认情况下，_SECURE_SCL的值为1。（注：Checked Iterator功能的启用与禁用和Debug Iterator功能的启用与禁用之间不会彼此影响）</p>
<p>&nbsp;&nbsp;&nbsp; 宏_SECURE_SCL_THROWS的值决定了Checked Iterator在发现越界时的运行时报错方式。如果_SECURE_SCL_THROWS被定义为1，则Checked Iterator在发现越界时会抛出异常std::out_of_rangce；如果_SECURE_SCL_THROWS被定义为0，则会调用CRT的非法参数处理例程（默认是终止程序）。宏_SECURE_SCL_THROWS的默认值为0。由于CRT的非法参数处理例程可以自行设置，所以程序可以改变默认终止运行的行为。（注：只有在_SECURE_SCL被定义为1时，_SECURE_SCL_THROWS才起作用）</p>
<p><br>--------------------------------------------------------------------------------<br>示例代码如下：<br>// cl /EHsc test1.cpp<br>#include &lt;vector&gt;<br>#include &lt;iostream&gt;<br>using namespace std;</p>
<p>void myInvalidParameterHandler(const wchar_t* expression,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const wchar_t* function, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const wchar_t* file, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int line, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uintptr_t pReserved)<br>{<br>&nbsp;&nbsp;&nbsp; cout &lt;&lt; "just ignore it" &lt;&lt; endl;<br>}</p>
<p>int main()<br>{<br>&nbsp;&nbsp;&nbsp; vector&lt;int&gt; v;<br>&nbsp;&nbsp;&nbsp; v.push_back(11);<br>&nbsp;&nbsp;&nbsp; v.push_back(22);</p>
<p>&nbsp;&nbsp;&nbsp; cout &lt;&lt; v[1] &lt;&lt; endl;</p>
<p>&nbsp;&nbsp;&nbsp; _set_invalid_parameter_handler(myInvalidParameterHandler);</p>
<p>&nbsp;&nbsp;&nbsp; cout &lt;&lt; v[2] &lt;&lt; endl;&nbsp;&nbsp; // out of range!</p>
<p>&nbsp;&nbsp;&nbsp; return 0;<br>}</p>
<p>--------------------------------------------------------------------------------</p>
<p>程序运行结果：<br>22<br>just ignore it<br>131074</p>
<p>&nbsp;&nbsp;&nbsp; 另外，如果定义_SECURE_SCL_THROWS为1，则在Debug版程序中需要在捕获异常之前先调用 _CrtSetReportMode(_CRT_ASSERT, 0)禁用ASSERT报错，并在捕获异常之后恢复。因为在程序抛出异常之前会先触发断言失败。示例代码如下：</p>
<p><br>--------------------------------------------------------------------------------<br>// cl /EHsc /D_DEBUG /MDd test2.cpp<br>#define _SECURE_SCL_THROWS 1</p>
<p>#include &lt;vector&gt;<br>#include &lt;iostream&gt;<br>#include &lt;crtdbg.h&gt;&nbsp; // For _CrtSetReportMode</p>
<p>using namespace std;</p>
<p><br>int main()<br>{<br>&nbsp;&nbsp;&nbsp; vector&lt;int&gt; v;<br>&nbsp;&nbsp;&nbsp; v.push_back(11);<br>&nbsp;&nbsp;&nbsp; v.push_back(22);</p>
<p>&nbsp;&nbsp;&nbsp; cout &lt;&lt; v[1] &lt;&lt; endl;</p>
<p>&nbsp;&nbsp;&nbsp; // disable ASSERT<br>&nbsp;&nbsp;&nbsp; int saved = _CrtSetReportMode(_CRT_ASSERT, 0);</p>
<p>&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; v[2] &lt;&lt; endl;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // out of range<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; catch (std::out_of_range &amp;) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; "out of range" &lt;&lt; endl;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; // restore ASSERT<br>&nbsp;&nbsp;&nbsp; _CrtSetReportMode(_CRT_ASSERT, saved);</p>
<p>&nbsp;&nbsp;&nbsp; return 0;<br>}</p>
<p>--------------------------------------------------------------------------------</p>
<p>程序运行结果：<br>22<br>out of range</p>
<p><br>--------------------------------------------------------------------------------<br>Part Two 库</p>
<p>迭代器与容器</p>
<p>&nbsp;&nbsp;&nbsp; 如果宏_SECURE_SCL为1，则所有标准库容器的迭代器都是Checked Iterator；如果宏_SECURE_SCL为0，则所有标准库容器的迭代器都是Unchecked Iterator。</p>
<p>&nbsp;&nbsp;&nbsp; 数组、指针及自定义迭代器类型均是Uncheck Iterator，但可以通过迭代器适配器stdext::checked_array_iterator和 stdext::checked_iterator把它们适配为Checked Iterator（注：VC对C++的所有扩展名字都位于名字空间stdext中）。例如，下面的代码片断使用 checked_array_iterator把一个数组（也可以是指针）适配为一个Checked Iterator：</p>
<p>// 示例代码片断<br>int a[]={1, 2, 3, 4, 5, 6};<br>int b[6];<br>copy(a, a + 6, stdext::checked_array_iterator&lt;int*&gt;(b, 5));</p>
<p>&nbsp;&nbsp;&nbsp; 如果宏_SECURE_SCL为1，则下面这些容器成员函数均会进行越界检查（Checked Iterator功能）：<br>&nbsp;&nbsp;&nbsp; basic_string::operator[]、 bitset::operator[]、deque::back、deque::front、deque::operator[]、 list::back、list::front、queue::back、queue::front、valarray::operator[]、 vector::back、vector::front、vector::operator[]。</p>
<p>算法</p>
<p>&nbsp;&nbsp;&nbsp; VC对C++标准库中部分算法进行了扩展。所有扩展算法均有一个对应的标准算法，且都位于名字空间stdext中，所在头文件与对应的标准算法相同，参数与用法也一样，唯一的区别是对参数迭代器的要求有所不同。这些扩展算法有两个版本，一个checked版本和一个unchecked版本，其函数名就是在标准算法的函数名之前添加前缀checked_和unchecked_。例如，标准算法std::copy有两个对应的扩展算法：stdext::check_copy和stdext::unchecked_copy。</p>
<p>当_SECURE_SCL为1时，<br>&nbsp;&nbsp;&nbsp; 如果标准算法有扩展版本，则此时标准算法相当于扩展算法的checked版本。<br>&nbsp;&nbsp;&nbsp; 如果作为算法参数的输出迭代器是一个Checked Iterator，那么在调用标准算法、checked版扩展算法和unchecked版扩展算法时，都将进行越界检查（例如，std::copy、 stdext::checked_copy和stdext::unchecked_copy）。<br>&nbsp;&nbsp;&nbsp; 如果作为算法参数的输出迭代器是一个Unchecked Iterator，那么在调用标准算法和checked版算法时，将产生编译警告（C4996）；而在调用unchecked版算法时不会产生警告信息。此时，都不会进行越界检查。</p>
<p>当_SECURE_SCL为0时，<br>&nbsp;&nbsp;&nbsp; 如果标准算法有扩展版本，则此时标准算法相当于扩展算法的unchecked版本。<br>&nbsp;&nbsp;&nbsp; 如果作为算法参数的输出迭代器是一个Checked Iterator，那么在调用标准算法、checked版扩展算法和unchecked版扩展算法时，都将进行越界检查。<br>&nbsp;&nbsp;&nbsp; 如果作为算法参数的输出迭代器是一个Unchecked Iterator，那么在调用checked版算法时，将产生编译警告（C4996）；而在调用标准算法和unchecked版本算法时不会产生警告信息。此时，都不会进行越界检查。</p>
<p>&nbsp;&nbsp;&nbsp; VC的扩展算法有（注：这里只列举checked版，unchecked版与checked版一一对应，只需要把函数名前缀checked_改为unchecked_即可）：<br>&nbsp;&nbsp;&nbsp; checked_adjacent_difference、checked_copy、checked_copy_backward、 checked_fill_n、checked_generate_n、checked_merge、checked_partial_sum、 checked_remove_copy、checked_remove_copy_if、checked_replace_copy、 checked_replace_copy_if、checked_reverse_copy、checked_rotate_copy、 checked_set_difference、checked_set_intersection、 checked_set_symmetric_difference、checked_set_union、 checked_uninitialized_copy、checked_uninitialized_fill_n、 checked_unique_copy。</p>
<p>&nbsp;</p>
<p>--------------------------------------------------------------------------------<br>其它编译问题</p>
<p>&nbsp;&nbsp;&nbsp; 请尝试编译如下代码（注意使用下面提供的编译选项！）：</p>
<p><br>--------------------------------------------------------------------------------<br>// 示例代码<br>// cl /EHsc /D_DEBUG /MDd /Za test.cpp<br>#define _SECURE_SCL_THROWS 1</p>
<p>#include &lt;string&gt;</p>
<p>int main()<br>{<br>&nbsp;&nbsp;&nbsp; return 0;<br>}</p>
<p>--------------------------------------------------------------------------------</p>
<p>我的VC9 SP1报错如下：</p>
<p>--------------------------------------------------------------------------------<br>test.cpp<br>D:\Microsoft Visual Studio 9.0\VC\INCLUDE\xstring(1566) : error C3861: &#8220;_Xran&#8221;<br>: 找不到标识符<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D:\Microsoft Visual Studio 9.0\VC\INCLUDE\xstring(1557): 编译类 模板 成<br>员函数&#8220;char &amp;std::basic_string&lt;_Elem,_Traits,_Ax&gt;::operator [](unsigned int)&#8221;<br>时<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _Elem=char,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _Traits=std::char_traits&lt;char&gt;,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _Ax=std::allocator&lt;char&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D:\Microsoft Visual Studio 9.0\VC\INCLUDE\xstring(2221): 参见对正在编译<br>的类 模板 实例化&#8220;std::basic_string&lt;_Elem,_Traits,_Ax&gt;&#8221;的引用<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _Elem=char,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _Traits=std::char_traits&lt;char&gt;,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _Ax=std::allocator&lt;char&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ]</p>
<p>--------------------------------------------------------------------------------</p>
<p>&nbsp;&nbsp;&nbsp; 看到上面的源代码和报错信息，估计有人会发疯了（我无意中挖掘出这个编译场景，抓狂了半天！）。确实，代码本身是没有任意问题的（根本就没有一行自己的代码嘛），那只可能出在编译器或者编译选项身上。由于我这里给出的是命令行选项，很容易发现问题所在。我当时遇到这个场景是在一个IDE环境中，费了好大的劲才从一堆选项中把元凶揪出来:-P<br>&nbsp; <br>&nbsp;&nbsp;&nbsp; 其实，这堆错误信息是由编译选项/Za引起的。/Za选项表示禁用编译器扩展，而我们这里讨论的Checked Iterator刚好就是编译器扩展功能，so&#8230;&#8230;over<br>文章出处：<a href="http://www.diybl.com/course/3_program/vc/vc_js/2008829/138422.html"><font color=#1d58d1>http://www.diybl.com/course/3_program/vc/vc_js/2008829/138422.html</font></a></p>
<img src ="http://www.cppblog.com/xosen/aggbug/78908.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xosen/" target="_blank">xosen</a> 2009-04-04 02:15 <a href="http://www.cppblog.com/xosen/articles/78908.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【设计模式】最简单常用的一种设计模式－－singleton（单件） </title><link>http://www.cppblog.com/xosen/articles/78907.html</link><dc:creator>xosen</dc:creator><author>xosen</author><pubDate>Fri, 03 Apr 2009 18:14:00 GMT</pubDate><guid>http://www.cppblog.com/xosen/articles/78907.html</guid><wfw:comment>http://www.cppblog.com/xosen/comments/78907.html</wfw:comment><comments>http://www.cppblog.com/xosen/articles/78907.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xosen/comments/commentRss/78907.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xosen/services/trackbacks/78907.html</trackback:ping><description><![CDATA[<div class=f14 id=read_tpc><font size=4><span style="COLOR: #ff0000">这是一篇论文，文章比较长，感兴趣的可以只看其中的部分内容。</span></font><br><br>＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝<br><br><br>摘&nbsp; 要 本文提出了三种Singleton模式的实现方式，并做了对比分析。<br>关键字 设计模式，Singleton<br>&nbsp; &nbsp; Singleton（单件）模式是一种很常用的设计模式。《Design Patterns》对它作的定义为：Ensure a class only has one instance, and provide a global point of access to it. 也就是说单件类在整个应用程序的生命周期中只能有一个实例存在，使用者通过一个全局的访问点来访问该实例。这是Singleton的两个最基本的特征，也是在实现的时候首先应该考虑的。Singleton的应用很广，它可以典型的被用来表示那些本性上具有唯一特性的系统组件，如数据库访问组件等。这一点在《Design Patterns》上有详细说明，在此就不细说了。<br><br>实现Singleton有很多途径，但都离不开两条最基本的原则。首先，要使得Singleton只有一个全局唯一的实例，我们通常的做法是将它的构造函数和拷贝构造函数私有化。再者，Singleton的全局唯一实例通常是一个static变量，这一点利用了语言的内在优势。本文给出的几种实现都比较简单，容易理解。在通常的情况下，它们足以满足要求。但缺点也是不可避免，以下我们逐一分析。 <br><br>一、基于模板函数的实现 <br><br>先看实现代码：<br><br>class MySingleton1<br><br>{<br><br>private:<br><br>&nbsp; &nbsp; MySingleton1(){ cout &lt;&lt; _T("Construct MySingleton1") &lt;&lt; endl; }<br><br>&nbsp; &nbsp; MySingleton1(const MySingleton1&amp;){} //拷贝构造函数<br><br>MySingleton1 &amp; operator =(const MySingleton1&amp;){} //赋值函数<br><br>&nbsp; &nbsp; template &lt;typename T&gt;<br><br>&nbsp; &nbsp; friend T&amp; GetInstanceRef();<br><br><br><br>public:<br><br>&nbsp; &nbsp; ~MySingleton1(){ cout &lt;&lt; _T("Destroy MySingleton1") &lt;&lt; endl; }<br><br><br><br>public:<br><br>&nbsp; &nbsp; void DoSomething(){ cout &lt;&lt; _T("Do something here in MySingleton1") &lt;&lt; endl; }<br><br>};<br><br>template &lt;typename T&gt;<br><br>T&amp; GetInstanceRef() //返回全局唯一对象的一个引用<br><br>{<br><br>&nbsp; &nbsp; static T _instance;<br><br>&nbsp; &nbsp; return _instance;<br><br>}<br><br>template &lt;typename T&gt;<br><br>T* GetInstancePtr() //返回全局唯一对象的指针<br><br>{<br><br>&nbsp; &nbsp; return &amp;GetInstanceRef&lt;T&gt;();<br><br>}<br><br>上面的代码中，MySingleton1是需要单实例化的类。下面的模板函数template &lt;typename T&gt; T&amp; GetInstanceRef()返回该类的唯一实例（静态变量_instance）的一个引用，另一个模板函数调用它返回该实例的指针。我们可以注意到以下几点：<br><br>1．&nbsp; &nbsp; MySingleton1的构造函数私有，防止了程序员随意构造它的实例。<br><br>2．&nbsp; &nbsp; 同样，拷贝构造函数MySingleton1(const MySingleton1&amp;)也被声明为私有。<br><br>3．&nbsp; &nbsp; 全局的模板函数template &lt;typename T&gt; T&amp; GetInstanceRef()是MySingleton1的友元。因为MySingleton1的构造函数已经声明为私有，为了让GetInstanceRef能顺利的构造静态变量_instance，我们不得不将它声明为MySingleton1的友元函数。<br><br><br><br>这样，我们的类MySingleton1就具有了Singleton特性了，而全局访问点就是两个模板函数。测试代码如下：<br><br>MySingleton1* myobj1;<br><br>myobj1 = GetInstancePtr&lt;MySingleton1&gt;();<br><br>myobj1-&gt;DoSomething();<br><br>GetInstanceRef&lt;MySingleton1&gt;().DoSomething();<br><br>&nbsp; &nbsp; 下面我们分析这种实现的缺点。由于模板函数GetInstanceRef被特化后要访问MySingleton1，它的声明必须在类（MySingleton1）声明之后（区分声明与实现），这与我们通常的使用方式不合。虽然它在其它方面表现的比较良好，但就这一个缺点已经使我不会再想使用它了。来看第二种可以实际使用的实现。<br><br><br><br>二、基于模板类的实现<br><br><br><br>&nbsp; &nbsp; 这种实现的基本思路是，做一个类让它来负责提供Singleton对象的生成与访问。由于它要构造Singleton对象，所以让它成为一个友元是理所当然的。下面看看实现代码：<br><br>template &lt;typename T&gt;<br><br>class SingletonWraper<br><br>{<br><br>public:<br><br>static T&amp; GetInstanceRef()<br><br>{<br><br>&nbsp; &nbsp; static T _instance;<br><br>&nbsp; &nbsp; return _instance;<br><br>}<br><br>static const T&amp; GetInstanceConst()<br><br>{<br><br>&nbsp; &nbsp; return GetInstanceRef();<br><br>}&nbsp; &nbsp; &nbsp; <br><br>static T* GetInstancePtr()<br><br>{<br><br>&nbsp; &nbsp; return &amp;GetInstanceRef();<br><br>}<br><br>};<br><br>#define DEFINE_SINGLETON(ClassName); \<br><br>public: \<br><br>friend class SingletonWraper&lt;ClassName&gt;; \<br><br>typedef class SingletonWraper&lt;ClassName&gt; SingletonWraper; \<br><br>typedef SingletonWraper SingletonInterface; \<br><br>private: \<br><br>ClassName(const ClassName&amp;){} \<br><br>ClassName&amp; operator=(const ClassName&amp;) \<br><br>{ \<br><br>&nbsp; &nbsp; return SingletonInterface::GetInstanceRef(); \<br><br>} \<br><br>private: //End of define DEFINE_SINGLETON(ClassName);<br><br>class MySingleton2<br><br>{<br><br>DEFINE_SINGLETON(MySingleton2);<br><br>private:<br><br>MySingleton2(){ cout &lt;&lt; _T("Construct MySingleton2") &lt;&lt; endl; }<br><br><br><br>public:<br><br>~MySingleton2(){ cout &lt;&lt; _T("Destroy MySingleton2") &lt;&lt; endl; }<br><br><br><br>public:<br><br>void DoSomething(){ cout &lt;&lt; _T("Do something here in MySingleton2") &lt;&lt; endl; }<br><br>};<br><br>&nbsp; &nbsp; 先看看SingletonWraper类，它提供的三个静态函数用于取得对Singleton对象的访问。再看下面的一个宏，它的作用是声明友元以及定义两个Singleton对象的访问点（SingletonWraper和SingletonInterface），并且，它还重载了拷贝构造函数以使访问的Singleton对象永远都是由GetInstanceRef惰性生成的一个实例。我们可以看见，使用这个SingletonWraper来包装Singleton类已经变得很简单了。我们只需要在需要Singleton化的类里面声明一条语句DEFINE_SINGLETON(MySingleton2);就可以了。但这还是有一些前提的，如构造函数（包括拷贝构造函数）私有以及析构函数公有。测试代码如下：<br><br>&nbsp; &nbsp; MySingleton2* myobj2;<br><br>&nbsp; &nbsp; myobj2 = SingletonWraper&lt;MySingleton2&gt;::GetInstancePtr();<br><br>&nbsp; &nbsp; myobj2-&gt;DoSomething();<br><br>&nbsp; &nbsp; MySingleton2::SingletonInterface::GetInstanceRef().DoSomething();<br><br><br><br>三、基于自身静态成员函数的实现<br><br><br><br>&nbsp; &nbsp; 这个实现不比前面的实现复杂，相反，更简单了。思路是从要实现Singleton的类自身入手，实现它的静态成员函数来提供全局的实例访问。这个实例的构造也是发生在它内部的一个静态成员函数里，所以，我们不用再使用友元来提供额外的访问权限。并且，我们也没有再使用任何模板。代码如下：<br><br>#define DECLARE_SINGLETON(ClassName); \<br><br>public: \<br><br>static ClassName&amp; GetInstanceRef() \<br><br>{ \<br><br>&nbsp; &nbsp; static ClassName _instance; \<br><br>&nbsp; &nbsp; return _instance; \<br><br>} \<br><br>static const ClassName&amp; GetInstanceConst() \<br><br>{ \<br><br>&nbsp; &nbsp; return GetInstanceRef(); \<br><br>} \<br><br>static ClassName* GetInstancePtr() \<br><br>{ \<br><br>&nbsp; &nbsp; return &amp;GetInstanceRef(); \<br><br>} \<br><br>private: \<br><br>ClassName(const ClassName&amp;){} \<br><br>ClassName&amp; operator=(const ClassName&amp;) \<br><br>{ \<br><br>&nbsp; &nbsp; return GetInstanceRef(); \<br><br>} \<br><br>private: \<br><br>static void operator delete(void *p, size_t n) \<br><br>{ \<br><br>&nbsp; &nbsp; ; /* 嘿嘿，什么都不要做.<br><br>&nbsp; &nbsp; &nbsp; &nbsp; 但要注意，析构函数已经执行。<br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 但对象并没有真正从内存卸载掉。*/ \<br><br>}//End of define DECLARE_SINGLETON(ClassName);<br><br><br><br>class MySingleton3<br><br>{<br><br>DECLARE_SINGLETON(MySingleton3);<br><br><br><br>private:<br><br>MySingleton3(){ cout &lt;&lt; _T("Construct MySingleton3") &lt;&lt; endl; }<br><br><br><br>public:<br><br>~MySingleton3(){ cout &lt;&lt; _T("Destroy MySingleton3") &lt;&lt; endl; }<br><br><br><br>public:<br><br>void DoSomething(){ cout &lt;&lt; _T("Do something here in MySingleton3") &lt;&lt; endl; }<br><br>};<br><br>实现Singleton的代码就一个宏定义而已，而使用它来使一个类拥有Singleton属性也只是调用一下这条宏。从使用上来看它应该是最简单的，看看下面的测试代码：<br><br>MySingleton3 *myobj3 = MySingleton3::GetInstancePtr();<br><br>myobj3-&gt;DoSomething();<br><br>delete myobj3;<br><br>MySingleton3::GetInstanceRef().DoSomething();<br><br>对比这里的测试代码和上一个的，可以发现，在使用过程中，这种方式也是最简单的。前面的三种方式都是在栈空间中创建对象，对象的销毁是在作用域边界上。细心的读者可能已经发现问题了。如果我们得到对象的指针后把它给delete了，则肯定就出问题了。对第一二种实现，我们没有重载delete操作符，delete之后指针将不再可用。而对第三种实现，我们有delete的重载函数，它阻止了对象的真正卸载。但在执行delete函数之前，析构函数已经执行了，因为全局的delete操作首先调用的是类的析构函数，再调用类的delete重载操作符函数。汇编代码清楚的显示了这一点：<br><br>MySingleton3::`scalar deleting destructor':<br><br>00412270&nbsp; push&nbsp; &nbsp; &nbsp; &nbsp; ebp<br><br>&#8230;&#8230;<br><br>0041228D&nbsp; mov&nbsp; &nbsp; &nbsp; &nbsp; ecx,dword ptr [ebp-4]<br><br>00412290&nbsp; call&nbsp; &nbsp; &nbsp; &nbsp; @ILT+175(MySingleton3::~MySingleton3) (004010b4)<br><br>00412295&nbsp; mov&nbsp; &nbsp; &nbsp; &nbsp; eax,dword ptr [ebp+8]<br><br>00412298&nbsp; and&nbsp; &nbsp; &nbsp; &nbsp; eax,1<br><br>0041229B&nbsp; test&nbsp; &nbsp; &nbsp; &nbsp; eax,eax<br><br>0041229D&nbsp; je&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MySingleton3::`scalar deleting destructor'+3Dh (004122ad)<br><br>0041229F&nbsp; push&nbsp; &nbsp; &nbsp; &nbsp; 4<br><br>004122A1&nbsp; mov&nbsp; &nbsp; &nbsp; &nbsp; ecx,dword ptr [ebp-4]<br><br>004122A4&nbsp; push&nbsp; &nbsp; &nbsp; &nbsp; ecx<br><br>004122A5&nbsp; call&nbsp; &nbsp; &nbsp; &nbsp; @ILT+70(MySingleton3::operator delete) (0040104b)<br><br>004122AA&nbsp; add&nbsp; &nbsp; &nbsp; &nbsp; esp,8<br><br>&#8230;&#8230;<br><br>前面的三个实现中Singleton的全局唯一对象是自动创建(惰性初始化)并自动销毁（在作用域边界上），而程序员非要执行delete操作的话将是错误的，这好比我们在程序中执行如下一段代码。<br><br>int i(0);<br><br>int* p = &amp;i;<br><br>delete p;<br><br>很显然，这是不被允许的。对这一点最好的处理方式是在delete的时候抛出一个异常，因为我们不允许程序员在这里使用delete操作。考虑下面的代码：<br><br>static void operator delete(void *p, size_t n) \<br><br>{ throw &#8211;1; }<br><br>相应的测试代码改为：<br><br>try { delete myobj3; /*试着卸载对象*/ }<br><br>catch(...) { cout &lt;&lt; _T("Your object cannot be deleted.") &lt;&lt; endl; /*失败*/ }<br><br><br><br>四、《Design Patterns》上的实现及其改进<br><br>&nbsp; &nbsp; 在《Design Patterns ---Elements of Reusable Object-Oriented Software》(英文版)第127页讨论Singleton模式时也给出了一个实现，但它存在一个严重的缺陷：没有考虑对象的销毁。以下是它给出的Sample代码：<br><br>class MazeFactory {<br><br>public:<br><br>static MazeFactory* Instance();<br><br><br><br>//existing interface goes here<br><br>protected:<br><br>MazeFactory();<br><br>private:<br><br>static MazeFactory* _instance;<br><br>};<br><br><br><br>MazeFactory* MazeFactory::_instance = 0;<br><br><br><br>MazeFactory* MazeFactory::Instance() {<br><br>if (_instance == 0) {<br><br>&nbsp; &nbsp; _instance = new MazeFactory;<br><br>}<br><br>return _instance;<br><br>}<br><br>&nbsp; &nbsp; 先分析一下它的实现策略。首先是构造函数访问受限（protected），然后声明了一个静态的对象指针，该指针的初始化（或者说该类的实例化）是在静态成员函数Instance里面。这里它并没有相应的对象卸载代码，然而在自由存储空间（堆空间）里生成的对象是不会自动卸载的。所以，经过改进，我得到了下面的代码。<br><br>class MySingleton4<br><br>{<br><br>private:<br><br>MySingleton4(){ cout &lt;&lt; _T("Construct MySingleton4") &lt;&lt; endl; } //构造函数私有&nbsp; &nbsp; ~MySingleton4(){ cout &lt;&lt; _T("Destroy MySingleton4") &lt;&lt; endl; } //析构函数放哪里都可以了<br><br>static MySingleton4* _instance;<br><br><br><br>public:<br><br>static MySingleton4&amp; GetInstanceRef()<br><br>{<br><br>&nbsp; &nbsp; if (_instance == 0)<br><br>&nbsp; &nbsp; &nbsp; &nbsp; _instance = new MySingleton4;<br><br>&nbsp; &nbsp; return *_instance;<br><br>}<br><br>static MySingleton4* GetInstancePtr()<br><br>{<br><br>&nbsp; &nbsp; return &amp;GetInstanceRef();<br><br>}<br><br>static ReleaseInstance()<br><br>{<br><br>&nbsp; &nbsp; if (_instance != 0)<br><br>&nbsp; &nbsp; {<br><br>&nbsp; &nbsp; &nbsp; &nbsp; delete _instance;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; _instance = 0;<br><br>&nbsp; &nbsp; }<br><br>}<br>public:<br><br>void DoSomething(){ cout &lt;&lt; _T("Do something here in MySingleton4") &lt;&lt; endl; }<br><br>};<br><br>MySingleton4* MySingleton4::_instance = 0; //Singleton对象初始化<br><br>static class DestructHelper //用于卸载MySingleton4对象的辅助类<br><br>{<br><br>public:<br><br>~DestructHelper(){ MySingleton4::ReleaseInstance(); }<br><br>} DestructHelperInstance; //辅助类静态实例<br><br>代码唯一的改进是增加了释放对象的静态函数ReleaseInstance。注意，在这个函数中_instance != 0判断以及后来的_instance = 0都是必不可少的，因为函数ReleaseInstance可能会被重复调用。将指针所指向的对象卸载后将指针置为0是一种非常好的编程习惯，它可以避免&#8220;野指针&#8221;的出现，而这通常是很危险的。接下来的类DestructHelper是用来辅助卸载MySingleton4的Singleton对象的，我们在它的公有析构函数里调用MySingleton4::ReleaseInstance()静态函数来完成工作。而DestructHelper的一个全局静态实例DestructHelperInstance会在适当的时候卸载掉，这就保证了析构函数~DestructHelper()得以被调用，从而卸载掉MySingleton4的Singleton对象。使用的时候，我们可以调用ReleaseInstance（）手动的卸载掉对象，然后再调用GetInstanceRef（）获得一个新的对象。如果我们不希望这样做，那么DestructHelperInstance的析构将保证堆空间里的对象得以被自动卸载。这样的处理方式增加了更多的灵活性。<br><br>但是，缺点还是有的。最主要的遗憾在于代码的重用上。第一、二种实现方式是基于模板技术的，代码可以很方便的重用，第三种方式虽然没有使用模板技术，但宏定义的使用也可以很好的保证代码的简单重用。最后的这种实现方式在代码重用上就显得稍微难了一点。我能想到的最佳解决办法仍然是使用宏（虽然我本人也很反对在C++里使用宏），一个用于定义MySingleton4类内部的处理，一个用于生成一个卸载辅助类的静态实例。第二个宏与模板有异曲同工的味道，不过，它还生成了一个与类型相关的静态变量。具体代码请见源程序清单。 <br><br>五、结束语 <br><br>本文全部代码在VC6.0里全部通过。<br><br>本文提出的只是作者写的几个比较简单的实现方式，但已经能满足大多数应用的需要了。更复杂的实现请参考<a id=url_1298 onclick="return checkUrl(this)" href="http://www.hoversoft.net/devinfo/0205doc/20Singleton/index.htm" target=_blank><font color=#0070af>http://www.hoversoft.net/devinfo/0205doc/20Singleton/index.htm</font></a>。本文作者&#8220;油箱&#8221;：<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#118;&#99;&#118;&#98;&#106;&#97;&#118;&#97;&#64;&#121;&#97;&#104;&#111;&#111;&#46;&#99;&#111;&#109;"><font color=#0070af>vcvbjava@yahoo.com</font></a>。欢迎大家讨论，以求共同进步。</div>
<img src ="http://www.cppblog.com/xosen/aggbug/78907.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xosen/" target="_blank">xosen</a> 2009-04-04 02:14 <a href="http://www.cppblog.com/xosen/articles/78907.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VS2005 warning C4251 needs to have dll-interface </title><link>http://www.cppblog.com/xosen/articles/78905.html</link><dc:creator>xosen</dc:creator><author>xosen</author><pubDate>Fri, 03 Apr 2009 17:38:00 GMT</pubDate><guid>http://www.cppblog.com/xosen/articles/78905.html</guid><wfw:comment>http://www.cppblog.com/xosen/comments/78905.html</wfw:comment><comments>http://www.cppblog.com/xosen/articles/78905.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xosen/comments/commentRss/78905.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xosen/services/trackbacks/78905.html</trackback:ping><description><![CDATA[<div class=content>　
<p>&nbsp; 程序中消除warning有两种方法：消极一点不去理他，反正不是error:-)；积极一点，则想办法去掉。去掉又用两种方法：一种使用#pragma warning(disable: xxxx)，眼不见，心不烦；另外就是找出解决问题的办法了。<br>&nbsp; 今天做dll库时，在struct中用到了stl：<br>&nbsp; class CLASS_TEST<br>&nbsp; {<br>&nbsp;&nbsp;&nbsp; ...<br>&nbsp; private:<br>&nbsp;&nbsp;&nbsp; std::vector&lt;MY_STRUCT&gt; m_structs;<br>&nbsp; }<br>&nbsp; 但是编译时，vs2005给出了warning C4251: 'CLASS_TEST::m_structs' : class 'std::vector&lt;_Ty&gt;' needs to have dll-interface to be used by clients of class &#8216;CLASS_TEST&#8217;的警告信息。费了很大的劲才解决掉，记录下来。<br><br>&nbsp; 在头文件中，定义宏<br>#ifdef MYDLL_EXPORTS<br>#define MYDLL_API __declspec(dllexport)<br>#else<br>#define MYDLL_API __declspec(dllimport)<br>#endif<br><br>&nbsp; 现在，在变量m_structs前，添加：<br>template class MYDLL_API std::allocator&lt;myStruct&gt;;<br>template class MYDLL_API std::vector&lt;myStruct, std::allocator&lt;myStruct&gt; &gt;;<br>&nbsp; 这样，即可以了。<br><br><br>另一篇:<br><br>1:情况一<br>如果类的定义里面仅含有 编译器内置的类型变量, int, float 等等. 或者成员函数仅使用了这些变量作为参数, 那么很简单.<br>直接<br>class __declspec(dllexport) YourClass</p>
<p>{<br>}<br>就行了.<br><br>2:情况二<br>如果类内部使用了别的类, 那么别的类最好也导出, 不然, 首先编译的时候会出现编译警告:<br><strong>&nbsp;warning C4251: needs to have dll-interface</strong> <br>意思是,你使用另外的一些类型/接口, 但是这些类型或接口没有导出. 当你的client使用这些类型/接口的时候, 会出错!<br>class __declspec(dllexport) YourClass</p>
<p>{<br>&nbsp;&nbsp; YourAnatherClass m_data; // 这里会 出现 warning 4251. 如果YourAnatherClass 没有导出的话.<br>}<br>解决办法就是: 在YourAnatherClass定义的地方加上<br>class __declspec(dllexport) YourAnatherClass <br>{<br>}<br>如上, 当你的YourAnatherClass没有导出的时候, dll的使用方会出现链接错误<br><br>3:情况三<br>当类的内部使用了STL模板的时候, 也会出现C4251警告, 情况会有所不同<br>class __declspec(dllexport) YourClass</p>
<p>{<br>&nbsp;&nbsp;&nbsp;vector&lt;int&gt; m_data; // 这里会 出现 warning 4251. 因为vector&lt;int&gt;类型没有被导出<br>}<br>上面的使用模板(无论是stl模板,还是自定义模板)的代码,编译dll时会出现C4251警告, 但是dll的使用方, 却不会出现链接错误!!!<br>这个因为, dll的使用方那里也有一套模板的定义, 当他们使用那个vector&lt;int&gt;的时候, 虽没有导出, 但是用户自己也有一套STL模板(或者是自定义的模板),用户会利用自己的模板实例化这个dll中没有导出的东西!<br><br>所以, 对于因为使用STL(或模板)出现的c4251警告, 关闭之即可<br>#pragma warning(push)<br>#pragma warning(disable:4251)<br>//your declarations that cause 4251<br>#pragma warning(pop)<br><br>若想不使用通过关闭警告的方式关闭警告, 那么就这样<br>1)对于用户自定义的模板<br>&nbsp;&nbsp; template class DLLImportExportMacro SomeTemplate&lt;int&gt;;<br>&nbsp;&nbsp; SomeTemplate&lt;int&gt; y;<br>2)对于STL的模板<br>&nbsp;&nbsp;&nbsp;&nbsp; template class DLLImportExportMacro std::allocator&lt;int&gt;<br>&nbsp; &nbsp;&nbsp; template class DLLImportExportMacro std::vector&lt;int,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::allocator&lt;int&gt; &gt;;<br>&nbsp;&nbsp;&nbsp;&nbsp; vector&lt;int&gt; m_data;<br></p>
<br>可以参看: <a href="http://www.unknownroad.com/rtfm/VisualStudio/warningC4251.html">http://www.unknownroad.com/rtfm/VisualStudio/warningC4251.html</a></div>
<img src ="http://www.cppblog.com/xosen/aggbug/78905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xosen/" target="_blank">xosen</a> 2009-04-04 01:38 <a href="http://www.cppblog.com/xosen/articles/78905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>