﻿<?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++博客-zhuxin-文章分类-More Effective C++</title><link>http://www.cppblog.com/zhuxin/category/20174.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 14 Jan 2013 09:55:08 GMT</lastBuildDate><pubDate>Mon, 14 Jan 2013 09:55:08 GMT</pubDate><ttl>60</ttl><item><title>基础议题</title><link>http://www.cppblog.com/zhuxin/articles/194529.html</link><dc:creator>zhuxin</dc:creator><author>zhuxin</author><pubDate>Sun, 04 Nov 2012 13:53:00 GMT</pubDate><guid>http://www.cppblog.com/zhuxin/articles/194529.html</guid><wfw:comment>http://www.cppblog.com/zhuxin/comments/194529.html</wfw:comment><comments>http://www.cppblog.com/zhuxin/articles/194529.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhuxin/comments/commentRss/194529.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhuxin/services/trackbacks/194529.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: red">条款1：仔细区别pointers和references</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;首先你必须认知一点，没有所谓的null reference。一个reference必须总是代表某个对象。所以如果你有一个变量，其目的是用来指向（代表）另一个对象，但是也有可能它不指向（代表）任何对象，那么你应该使用pointer，因为你可以将pointer设为null。换个角度看，如果这个变量总是必须代表一个对象，也就是说如果你的设计并不允许这个变量为null，那么你应该使用reference。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;what about this?<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char *pc = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char &amp;rc = *pc;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这是有害的行为，其结果无可预期，编译器可以产生任何可能的输出。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由于reference一定得代表某个对象，C++因此要求references必须有初值：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string &amp;rs;&nbsp;&nbsp;&nbsp;//错误！references必须初始化<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string s("xyzzy");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string &amp;rs = s; //没问题，rs指向s<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;但是pointers就没有这样的限制：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string *ps; //未初始化的指针，有效，但风险高<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（没有所谓的null reference）这个事实意味使用references可能会比使用pointers更富效率。这是因为使用reference之前不需测试其有效性：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void printDouble(const double &amp;rd)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout &lt;&lt; rd; //不需测试rd; 它一定代表某个double<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果使用pointers，通常就得测试它是否为null:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void printDouble(const double *pd)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (pd)&nbsp;&nbsp;&nbsp;//检查是否为null pointer<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<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;cout &lt;&lt; *pd;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pointers和references之间的另一个重要差异就是，pointers可以被重新赋值，指向另一个对象，reference却总是指向（代表）它最初获得的那个对象：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string s1("Nancy");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string s2("Clancy");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string &amp;rs = s1;&nbsp;&nbsp;&nbsp;//rs代表s1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string *ps = &amp;s1;&nbsp;&nbsp;&nbsp;//ps指向s1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rs = s2;&nbsp;&nbsp;&nbsp;//rs仍然代表s1，但是s1的值现在变成了"Clancy".<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ps = &amp;s2;&nbsp;&nbsp;&nbsp;//ps现在指向s2；s1没有变化<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;还有其他情况也需要使用reference，例如当你实现某些操作符的时候。最常见的例子就是operator[]。这个操作符很特别地必须返回某种（能够被当做assignment赋值对象）的东西：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vector&lt;int&gt; v(10);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v[5] = 10;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果operator[]返回pointer，上述最后一个语句就必须写成这样子：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*v[5] = 10;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;但这使v看起来好像是个以指针形成的vector，事实上它不是。为了这个因素，你应该总是令operator[]返回一个referenc。<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: red">&nbsp;&nbsp;</span><span style="color: red">结论:当你知道你需要指向某个东西，而且绝不会改指向其他东西，或是当你实现一个操作符而其语法需求无法由pointers达成，你就应该选择references。任何其他时候，请采用pointers。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;条款2：最好使用C++转型操作符<br /></span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C++四个新的转型操作符：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static_cast：转型操作。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const_cast:移除某个对象的常量性。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dynamic_cast：将指向base class objects之pointers或references转型为指向derived（或sibling base）class objects之pointers或references，并得知转型是否成功。如果转型失败，会以一个null指针（当转型对象是指针）或一个exception（当转型对象时reference）表现出来。第二个的用途是找出被某对象占用的内存的起始点。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reinterpret_cast：最常用途是转换函数指针性别。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef void (*FuncPtr)();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FuncPtr funcPtrArray[10];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;假设由于某种原因，你希望将以下函数的一个指针放进funcPtrArray中：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int doSomething（）；<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用reinterpret_cast，可以强迫编译器了解你的意图：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;funcPtrArray[0] = reinterpret_cast&lt;FuncPtr&gt;(&amp;doSomethind);</span>&nbsp;<br /><span style="color: red">&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000">条款3：绝对不要以多态方式</span><font color="#ff0000">处理数组</font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class BST{};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class BalancedBST:public BST{};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void printBSTArray(ostream&amp; s, const BST array[], int numElements)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 0; i &lt; numElements; ++i)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<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;s &lt;&lt; array[i];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当你将一个由BST对象组成的数组传给此函数，没问题：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BST BSTArray[10];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printBSTArray(cout, BSTArray, 10);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;然而如果你将一个BalancedBST对象所组成的数组交给printBSTArray函数，会发生什么事：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BalancedBST bBSTArray[10];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printBSTArray(cout, bBSTArray, 10);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;你的编译器会被误导。这种情况下它仍假设数组中每一元素的大小是BST的大小，但其实每一元素的大小事BalanceBST的大小。由于derived classes通常比其base classes有更多的data members，所以derived class objects通常都比其base class objects来得大。这样的话，结果无可预期。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果你尝试通过一个base class指针，删除一个derived class objects组成的数组，那么上述问题还会以另一种不同面貌出现。下面是你可能做出的错误尝试：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void deleteArray(ostream&amp; logStream, BST array[])<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logStream &lt;&lt; "Deleting array at adress "<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;&lt;&lt; static_cast&lt;void*&gt;(array) &lt;&lt; '\n';<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete [] array;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BalancedBST *balTreeArray = new BalancedBST[50];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deleteArray(cout, balTreeArray);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C++语言规格中说，通过base class指针删除一个由derived classes objects构成的数组，其结果未有定义。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src ="http://www.cppblog.com/zhuxin/aggbug/194529.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhuxin/" target="_blank">zhuxin</a> 2012-11-04 21:53 <a href="http://www.cppblog.com/zhuxin/articles/194529.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>