• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            任何時(shí)候都適用的20個(gè)C++技巧(轉(zhuǎn)載)

            這些小技巧之所以特別,是因?yàn)檫@些信息通常吧不能在C++書籍或者網(wǎng)站上找到。比如說(shuō),成員指針,即使對(duì)于高級(jí)程序員也是比較棘手,和易于產(chǎn)生bugs的,是應(yīng)該盡量避免的問(wèn)題之一。

            <翻 by凌云健筆>

            What makes these tips special is that the information they provide usually cannot be found in C++ books or Web sites. For example, pointers to members are one of the most evasive, tricky, and bug-prone issues for even advanced users.

            by Danny Kalev

            ====================================
            Page 1: Introduction 介紹

            接下來(lái)的這幾條技巧主要集中于實(shí)用技術(shù)和一些晦澀知識(shí)上;它們與特殊的平臺(tái)、編程領(lǐng)域、或編譯器無(wú)關(guān)。因此,它們適用于所有的C++程序員。本人把這些技巧劃分為五大類:編碼風(fēng)格、內(nèi)存管理、性能提升、面向?qū)ο蟮脑O(shè)計(jì),和標(biāo)準(zhǔn)模板庫(kù)(STL)五方面的一般準(zhǔn)則。

            The following tips are a collection of general hands-on techniques and recondite pieces of knowledge not associated with a specific platform, programming domain, or compiler. As such, they can be of use to all C++ programmers. I grouped the tips into five major categories: general guidelines for coding style, memory management, performance enhancement, object-oriented design, and the Standard Template Library (STL).
            ====================================
            First Four: Guidelines for Better Coding Style 較好編程風(fēng)格所要遵循的一些準(zhǔn)則

            在這個(gè)類別中,所涉及的技巧是各級(jí)C++的程序員均會(huì)經(jīng)常提及的問(wèn)題。舉個(gè)例子,我很驚訝的發(fā)現(xiàn),有很多具有一定經(jīng)驗(yàn)的程序員仍舊不知道.h是一種過(guò)時(shí)的標(biāo)準(zhǔn)頭文件標(biāo)識(shí)方式,不會(huì)正確的應(yīng)用名空間,不了解在向臨時(shí)對(duì)象綁定引用時(shí)所要遵循的準(zhǔn)則。這些問(wèn)題以及一些其他問(wèn)題將在這里進(jìn)行討論。首先,我們先解釋過(guò)時(shí)的頭文件命名符號(hào)<xxx.h>與現(xiàn)代的符合標(biāo)準(zhǔn)的<xxx>頭文件命名符號(hào)之間的區(qū)別。接下來(lái),我們探究一些由于編譯器限制以及相關(guān)的語(yǔ)言規(guī)則深?yuàn)W性質(zhì)所帶來(lái)的C++“陰暗角落”;這點(diǎn)往往有許多程序員混淆不清。例如,用逗號(hào)分隔的表達(dá)式,對(duì)右值綁定引用的規(guī)則等。最后,我們將學(xué)習(xí)如何在程序的啟動(dòng)之前調(diào)用某個(gè)函數(shù)。

            技巧1:用<iostream.h>還是<iostream>?這不是一個(gè)問(wèn)題!

              很多的C++程序員依舊使用<iostream.h>,而非最新的、標(biāo)準(zhǔn)編譯生成的<iostream>庫(kù)。這兩個(gè)庫(kù)之間有什么區(qū)別呢?首先,針對(duì)用.h作為標(biāo)準(zhǔn)頭文件的標(biāo)識(shí)符這一問(wèn)題,五年前就已經(jīng)不被推薦使用了。在新的代碼中再使用這種不被認(rèn)同的表示方式絕不是一個(gè)好主意。在功能方面,<iostream>包括模板化的IO類,它同時(shí)支持窄字符和寬字符;而<iostream.h>卻只支持以char為導(dǎo)向的流。第三,在C++的iostream接口標(biāo)準(zhǔn)規(guī)格在許多微妙的方面發(fā)生了變化。所以,<iostream>的接口與實(shí)現(xiàn)與<iostream.h>存在著一定得差異。最后,,<iostream>組件聲明于std命名空間中,而<iostream.h>組件是全局性的。

              因?yàn)槎咧g存在著這些重大分歧,你不能在同一程序中混合使用兩個(gè)庫(kù)。作為一條準(zhǔn)則:使用<iostream>代替<iostream.h>,除非你處理了那些只與<iostream.h>兼容的遺留代碼。

            Tip 1: <iostream.h> or <iostream>?
              Many C++ programmers still use <iostream.h> instead of the newer, standard compliant <iostream> library. What are the differences between the two? First, the .h notation of standard header files was deprecated more than five years ago. Using deprecated features in new code is never a good idea. In terms of functionality, <iostream> contains a set of templatized I/O classes which support both narrow and wide characters, as opposed to <iostream.h> which only supports char-oriented streams. Third, the C++ standard specification of iostream's interface was changed in many subtle aspects. Consequently, the interfaces and implementation of <iostream> differ from those of <iostream.h>. Finally, <iostream> components are declared in namespace std whereas <iostream.h> components are global.

              Because of these substantial differences, you cannot mix the two libraries in one program. As a rule, use <iostream> unless you're dealing with legacy code that is only compatible with <iostream.h>.

            技巧2:左值的引用,要注意!

              左值和右值是C++編程的基本概念。從本質(zhì)上說(shuō),右值是一種不能出現(xiàn)在賦值表達(dá)式左側(cè)的表達(dá)式。相較而言,左值是一個(gè)你可以寫入數(shù)值的對(duì)象或者內(nèi)存塊。引用可以指向左值,也可以是右值。但是,由于對(duì)右值的語(yǔ)言限制,所以你必須了解在向右值綁定引用時(shí)所要遵循的規(guī)則。

              只要引用綁定的對(duì)象是一個(gè)const類型,那么就可以對(duì)右值綁定引用。這一規(guī)則背后的理由很簡(jiǎn)單:你不能試圖去改變一個(gè)右值,常量的引用保證了程序不會(huì)通過(guò)引用去改變右值。在下面的例子中,函數(shù)f()輸入一個(gè)const int的引用:

            void f(const int & i);
            int main()
            {
            f(
            2); /* OK */
            }

            程序?qū)⒂抑?作為一個(gè)參數(shù)傳入函數(shù)f()。在實(shí)時(shí)運(yùn)行中,C++會(huì)生成一個(gè)類型為int值為2的臨時(shí)對(duì)象,并將其與引用i綁定。臨時(shí)對(duì)象和他的引用存在與函數(shù)f()從觸發(fā)到返回整個(gè)過(guò)程;函數(shù)返回后,他們被立即銷毀。注意,如果我們聲明引用i時(shí)沒(méi)有使用const標(biāo)識(shí)符,函數(shù)f()就可以修改它的參數(shù),從而引起未定義的行為。所以,你只能向常量對(duì)象綁定引用。

              同樣的準(zhǔn)則適用于自定義對(duì)象類性。只有當(dāng)臨時(shí)對(duì)象是常量時(shí),你才能綁定引用。

            Tip 2: Binding a Reference to an Rvalue
              Rvalues and lvalues are a fundamental concept of C++ programming. In essence, an rvalue is an expression that cannot appear on the left-hand side of an assignment expression. By contrast, an lvalue refers to an object (in its wider sense), or a chunk of memory, to which you can write a value. References can be bound to both rvalues and lvalues. However, due to the language's restrictions regarding rvalues, you have to be aware of the restrictions on binding references to rvalues, too.

              Binding a reference to an rvalue is allowed as long as the reference is bound to a const type. The rationale behind this rule is straightforward: you can't change an rvalue, and only a reference to const ensures that the program doesn't modify an rvalue through its reference. In the following example, the function f() takes a reference to const int:

            void f(const int & i);
            int main()
            {
            f(2); /* OK */
            }

              The program passes the rvalue 2 as an argument to f(). At runtime, C++ creates a temporary object of type int with the value 2 and binds it to the reference i. The temporary and its reference exist from the moment f() is invoked until it returns; they are destroyed immediately afterwards. Note that had we declared the reference i without the const qualifier, the function f() could have modified its argument, thereby causing undefined behavior. For this reason, you may only bind references to const objects.

            技巧3:奇怪的逗號(hào)分割表達(dá)式

              逗號(hào)分隔的表達(dá)式是從C繼承而來(lái)的。你很有可能會(huì)在使用for-循環(huán)和while-循環(huán)的時(shí)候經(jīng)常使用這樣的表達(dá)式。然而,在這方面的語(yǔ)言規(guī)則還遠(yuǎn)不直觀。首先,讓我們來(lái)看看什么是逗號(hào)分隔的表達(dá)式:這種表達(dá)式可能包含一個(gè)或多個(gè)用逗號(hào)分隔的子表達(dá)式。例如:

            if(++x, --y, cin.good()) /*three expressions 三個(gè)表達(dá)式*/

              IF條件包含由逗號(hào)分隔的三個(gè)表達(dá)式。C++確保每表達(dá)式都被執(zhí)行,產(chǎn)生其副作用。然而,整個(gè)表達(dá)式的值僅是最右邊的表達(dá)式的結(jié)果。因此,只有cin.good()返回true時(shí),上述條件才為真。再舉一個(gè)逗號(hào)表達(dá)式的例子:

            int j=10;
            int i=0;
            while( ++i, --j)
            {
            /*只要j不為0,在循環(huán)執(zhí)行*/
            }

            Tip 3: Comma-Separated Expressions
              Comma-separated expressions were inherited from C. It's likely that you use such expressions in for- and while-loops rather often. Yet, the language rules in this regard are far from being intuitive. First, let's see what a comma separated expression is. An expression may consist of one or more sub-expressions separated by commas. For example:

            if(++x, --y, cin.good()) /*three expressions */

              The if condition contains three expressions separated by commas. C++ ensures that each of the expressions is evaluated and its side effects take place. However, the value of an entire comma-separated expression is only the result of the rightmost expression. Therefore, the if condition above evaluates as true only if cin.good() returns true. Here's another example of a comma expression:

            int j=10;
            int i=0;
            while( ++i, --j)
            {
            /*if (j!=0) loop*/
            }

            技巧4:如何在程序啟動(dòng)前調(diào)用函數(shù)?

              某些應(yīng)用程序需要在調(diào)用主要程序之前開(kāi)始啟動(dòng)功能。例如,polling(輪詢),billing(***),和logger(日志記錄)等函數(shù)必須在調(diào)用實(shí)際的程序之前開(kāi)始。最簡(jiǎn)單的實(shí)現(xiàn)這一目標(biāo)的方式是調(diào)用一個(gè)全局對(duì)象的構(gòu)造函數(shù)。因?yàn)閺母拍钌险f(shuō),全局對(duì)象是在程序開(kāi)始之構(gòu)造的,這個(gè)函數(shù)會(huì)在main()開(kāi)始之前返回。例如:

            復(fù)制代碼
            class Logger
            {
            public:
            Logger()
            {
            activate_log();
            }
            };
            Logger log;
            /*global instance*/

            int main()
            {
            record
            * prec=read_log();
            //.. application code
            }
            復(fù)制代碼

              全局對(duì)象log在main()開(kāi)始之前完成構(gòu)造。在構(gòu)造過(guò)程中,log觸發(fā)了函數(shù)activate_log()。當(dāng)main()開(kāi)始后,它就可以從日志文件中讀取數(shù)據(jù)。

            Tip 4: Calling a Function Before Program's Startup
              Certain applications need to invoke startup functions that run before the main program starts. For example, polling, billing, and logger functions must be invoked before the actual program begins. The easiest way to achieve this is by calling these functions from a constructor of a global object. Because global objects are conceptually constructed before the program's outset, these functions will run before main() starts. For example:

            class Logger
            {
            public:
            Logger()
            {
            activate_log();
            }
            };
            Logger log; /*global instance*/

            int main()
            {
            record * prec=read_log();
            //.. application code
            }
            The global object log is constructed before main() starts. During its construction, log invokes the function activate_log(). Thus, when main() starts, it can read data from the log file.


            毫無(wú)疑問(wèn),內(nèi)存管理是在C++編程中最復(fù)雜和最易出錯(cuò)的問(wèn)題之一。能夠直接地訪問(wèn)原始內(nèi)存,動(dòng)態(tài)地分配內(nèi)存空間,以及C++的高效性決定它必須有一些非常嚴(yán)格的規(guī)則;如果你不遵守將難以避免那些內(nèi)存相關(guān)的錯(cuò)誤或者程序運(yùn)行時(shí)的崩潰。

              指針是訪問(wèn)內(nèi)存的主要手段。 C++可以分為兩個(gè)主要類別:指向數(shù)據(jù)的指針和指向函數(shù)的指針。第二大類又可以分為兩個(gè)子類類:普通函數(shù)指針和成員函數(shù)指針。在下面的技巧中,我們將深入探討這些問(wèn)題,并學(xué)習(xí)一些方法,簡(jiǎn)化指針的使用,同時(shí)隱藏它們的笨拙語(yǔ)法。

              指向函數(shù)的指針很可能是C++中一種最不具可讀性的語(yǔ)法結(jié)構(gòu)。唯一的可讀性更差的似乎只有成員指針。第一個(gè)技巧會(huì)教你如何提高普通的函數(shù)指針的可讀性。這是你理解C++成員指針的前提。接下來(lái),我們將學(xué)習(xí)如何避免內(nèi)存碎片,并告訴你其可怕的后果。最后,我們討論delete和delete []的正確使用方法;它常常會(huì)是眾多錯(cuò)誤和誤解的來(lái)源。

            技巧5:函數(shù)指針的繁瑣語(yǔ)法?!見(jiàn)鬼去吧!!

            你能告訴我下面定義的含義么?

            void (*p[10]) (void (*)());

              p是“一個(gè)包含10個(gè)函數(shù)指針的數(shù)組,這些函數(shù)返回為空,其參數(shù)為{【(另外一個(gè)無(wú)參數(shù)返回為空)的函數(shù)】的指針}。”如此繁瑣的語(yǔ)法幾乎難以辨認(rèn),難道不是嗎?解決之道在何方?你可以通過(guò)typedef來(lái)合理地大大地去簡(jiǎn)化這些聲明。首先,聲明一個(gè)無(wú)參數(shù)、返回空的函數(shù)的指針的typedef,如下所示:

            typedef void (*pfv)();

              接下來(lái) 聲明另一個(gè)typedef,一個(gè)指向參數(shù)為pfv返回為空的函數(shù)的指針:

            typedef void (*pf_taking_pfv) (pfv);

              現(xiàn)在,再去聲明一個(gè)含有10個(gè)這樣指針的數(shù)組就變得輕而易舉,不費(fèi)吹灰之力了:

            pf_taking_pfv p[10]; /*等同于void (*p[10]) (void (*)()); 但更具可讀性*/

            技巧6:函數(shù)指針的枝枝節(jié)節(jié)

              類有兩類成員:函數(shù)成員和數(shù)據(jù)成員。同樣,也就有兩種類別的成員指針:成員函數(shù)指針和數(shù)據(jù)成員指針。后者不太常見(jiàn),因?yàn)椋话銇?lái)說(shuō),類是沒(méi)有公共數(shù)據(jù)成員的。當(dāng)使用傳統(tǒng)C代碼的時(shí)候,數(shù)據(jù)成員指針才是有用的,因?yàn)閭鹘y(tǒng)C代碼中包含的結(jié)構(gòu)體或類是具有公開(kāi)數(shù)據(jù)成員的。

              在C++中,成員指針是最為復(fù)雜的語(yǔ)法結(jié)構(gòu)之一;可是,這卻是一個(gè)非常強(qiáng)大而重要的特性。它們可以使您在不知道這個(gè)函數(shù)的名字的前提下調(diào)用一個(gè)對(duì)象的成員函數(shù)。這是非常方便的回調(diào)實(shí)現(xiàn)。同樣的,你可以使用一個(gè)數(shù)據(jù)成員指針來(lái)監(jiān)測(cè)和修改數(shù)據(jù)成員的值,而不必知道它的名字。

            指向數(shù)據(jù)成員的指針
              雖然成員指針的語(yǔ)法可能會(huì)顯得有點(diǎn)混亂,但是它與普通指針的形式比較一致和類似,只需要在星號(hào)之前加上類名::即可。例如,如果一個(gè)普通的整形指針如下所示:

            int * pi;

              那么,你就可以按照下面的方式來(lái)定義一個(gè)指向類A的整形成員變量的指針:

            int A::*pmi; /* pmi is a pointer to an int member of A*/

              你需要按照這樣的方式初始化成員指針:

            復(fù)制代碼
            class A
            {
            public:
            int num;
            int x;
            };
            int A::*pmi = & A::num; /* 1 */
            復(fù)制代碼

              標(biāo)號(hào)1的語(yǔ)句聲明了一個(gè)指向類A的整形成員的指針,它用A類對(duì)象中的成員變量num的地址實(shí)現(xiàn)了初始化。使用pmi和內(nèi)置操作符.*,你可以監(jiān)測(cè)和修改任何一個(gè)A類型的對(duì)象中的num的值。

            A a1, a2;
            int n=a1.*pmi; /* copy a1.num to n */
            a1.
            *pmi=5; /* assign the value 5 to a1.num */
            a2.
            *pmi=6; /* assign the value 6 to a2.num */

              如果有一個(gè)指向A的指針,你必須使用->*操作符:

            A * pa=new A;
            int n=pa->*pmi;
            pa
            ->*pmi=5;

            成員函數(shù)指針
              它由成員函數(shù)的返回類型,類名加上::,指針名稱,函數(shù)的參數(shù)列表幾部分組成。例如,類型A的一個(gè)成員函數(shù)返回一個(gè)int,無(wú)參數(shù),那么其函數(shù)指針應(yīng)該定義如下(注意兩對(duì)括號(hào)是必不可少的):

            復(fù)制代碼
            class A
            {
            public:
            int func ();
            };

            int (A::*pmf) ();
            復(fù)制代碼

              換句話說(shuō),pmf是一個(gè)指向類A的成員函數(shù)的指針,類A的成員函數(shù)返回int指針,無(wú)參數(shù)。事實(shí)上,一個(gè)成員函數(shù)指針看起來(lái)和普通的函數(shù)指針相似,除了它包含函數(shù)名加上::操作符。您可以使用.*操作符來(lái)調(diào)用pmf指向的成員函數(shù):

            pmf=&A::func;
            A a;
            (a.
            *pmf)(); /* invoke a.func() */

              如果有的是一個(gè)對(duì)象的指針,你必須使用->*操作符:

            A *pa=&a;
            (pa
            ->*pmf)(); /*calls pa->func() */

              成員函數(shù)指針遵循多態(tài)性。因此,如果你通過(guò)這樣一個(gè)指針調(diào)用虛成員函數(shù),則會(huì)實(shí)現(xiàn)動(dòng)態(tài)調(diào)用。但是需要注意的是,你不能將成員函數(shù)指針指向一個(gè)類的構(gòu)造函數(shù)或者析構(gòu)函數(shù)的地址。

            技巧7:內(nèi)存碎片,No!!No!!No!!

              通常而言,應(yīng)用程序是不受內(nèi)存泄露影響的;但如果應(yīng)用程序運(yùn)行很長(zhǎng)一段時(shí)間,頻繁的分配和釋放內(nèi)存則會(huì)導(dǎo)致其性能逐漸下降。最終,程序崩潰。這是為什么呢?因?yàn)榻?jīng)常性的動(dòng)態(tài)內(nèi)存分配和釋放會(huì)造成堆碎片,尤其是應(yīng)用程序分配的是很小的內(nèi)存塊。支離破碎的堆空間可能有許多空閑塊,但這些塊既小又不連續(xù)的。為了證明這一點(diǎn),請(qǐng)參看一下下面的堆空間表示。0表示空閑內(nèi)存塊,1表示使用中的內(nèi)存塊:

            100101010000101010110

              上述堆是高度分散。如果分配一個(gè)包含五個(gè)單位(即五個(gè)0)內(nèi)存塊,這將是不可能的,盡管系統(tǒng)總共中還有12個(gè)空閑空間單位。這是因?yàn)榭捎脙?nèi)存是不連續(xù)的。另一方面,下面的堆可用內(nèi)存空間雖然少,但它卻不是支離破碎的:

            1111111111000000

              你能做些什么來(lái)避免這樣的堆碎片呢?首先,盡可能少的使用動(dòng)態(tài)內(nèi)存。在大多數(shù)情況下,可以使用靜態(tài)或自動(dòng)儲(chǔ)存,或者使用STL容器。其次,盡量分配和重新分配大塊的內(nèi)存塊而不是小的。例如,不要為一個(gè)單一的對(duì)象分配內(nèi)存,而是一次分配一個(gè)對(duì)象數(shù)組。當(dāng)然,你也可以將使用自定義的內(nèi)存池作為最后的手段。

            技巧8:對(duì)于Delete 和 Delete [],你要區(qū)分清楚

              在程序員當(dāng)中流傳有一個(gè)眾所周知的傳說(shuō):對(duì)于內(nèi)置類型,使用delete 代替delete []來(lái)釋放內(nèi)存是完全可以的。例如,

            int *p=new int[10];
            delete p;
            /*bad; should be: delete[] p*/

              這是完全錯(cuò)誤的方式。在C++標(biāo)準(zhǔn)明確指出,使用delete來(lái)釋放任何類型的動(dòng)態(tài)分配的數(shù)組,將會(huì)導(dǎo)致未定義行為。事實(shí)上,在某些平臺(tái)上應(yīng)用程序使用delete而非delete[]但是不死機(jī)可以歸結(jié)為純粹的運(yùn)氣:例如,針對(duì)內(nèi)置數(shù)據(jù)類型,Visual C++通過(guò)調(diào)用free()同時(shí)實(shí)現(xiàn)了delete[]和delete。但是,我們并不能保證的Visual C++未來(lái)版本中將仍然堅(jiān)持這么做。此外,也不會(huì)保證這個(gè)代碼將適用于其他的編譯器。總括來(lái)說(shuō),使用delete來(lái)代替delete [],或者用delete []來(lái)代替delete都很危險(xiǎn),應(yīng)當(dāng)盡量去避免。


            Nine to 11: Performance Enhancements

            下面所列出的是三個(gè)相當(dāng)簡(jiǎn)單但又不是很常見(jiàn)的技術(shù),在不犧牲程序可讀性、不修改程序設(shè)計(jì)的前提下,提高程序的性能。例如,程序員往往不太清楚,只是簡(jiǎn)單的對(duì)數(shù)據(jù)成員進(jìn)行重新排序就可以大大減少它的大小。這種優(yōu)化可以提高性能,如果應(yīng)用程序使用到了這些對(duì)象的數(shù)組,效果尤其明顯。此外,我們還將學(xué)習(xí)前綴和后綴操作符之間的差異;在重載操作符中,這是一個(gè)很重要的問(wèn)題。最后,我們將學(xué)習(xí)一些消除臨時(shí)對(duì)象的創(chuàng)建的方法。

            技巧9:類成員對(duì)齊方式的優(yōu)化

              只需改變類成員的聲明順序就可以改變這個(gè)類的大小:

            struct A
            {
            bool a;
            int b;
            bool c;
            };
            /*sizeof (A) == 12*/

              在我的機(jī)器上,sizeof (A) 等于12。結(jié)果看起來(lái)非常的出乎意料,因?yàn)锳的成員大小之和僅僅是6個(gè)字節(jié),多余的6個(gè)字節(jié)來(lái)自何方呢?編譯器在每個(gè)bool類型成員的后面插入了各插入三個(gè)填充字節(jié),使得它四字節(jié)邊界對(duì)齊。你可以按照下面的方式重新組織數(shù)據(jù)成員減少A的大小:

            struct B
            {
            bool a;
            bool c;
            int b;
            };
            // sizeof (B) == 8

              這次編譯器只是在成員c的后面插入兩個(gè)填充字節(jié)。因?yàn)閎占4字節(jié),它自然就word邊界對(duì)齊,而不需要額外的填充字節(jié)。

             

            技巧10:明確前綴后綴操作符之間的差異

              內(nèi)置的++操作符可以放在操作數(shù)的兩邊:

            int n=0;
            ++n; /*前綴*/
            n
            ++; /*后綴*/

              你一定知道前綴操作符首先改變操作數(shù),然后再使用它的值。比如:

            int n=0, m=0;
            n
            = ++m; /*first increment m, then assign its value to n*/
            cout
            << n << m; /* display 1 1*/

              在這個(gè)例子中,在賦值之后,n等于1;因?yàn)樗窃趯賦予n之前完成的自增操作。

            int n=0, m=0;
            n
            = m++; /*first assign m's value to n, then increment m*/
            cout
            << n << m; /*display 0 1*/

              在這個(gè)例子中,賦值之后,n等于0;因?yàn)樗窍葘賦予n,之后m再加1。

              為了更好的理解前綴操作符和后綴操作符之間的區(qū)別,我們可以查看這些操作的反匯編代碼。即使你不了解匯編語(yǔ)言,你也可以很清楚地看到二者之間的區(qū)別,注意inc指令出現(xiàn)的位置:

            復(fù)制代碼
            /*disassembly of the expression: m=n++;*/
            mov ecx, [ebp-0x04] /*store n's value in ecx register*/
            mov [ebp-0x08], ecx /*assign value in ecx to m*/
            inc dword ptr [ebp-0x04] /*increment n*/



            /*disassembly of the expression: m=++n;*/
            inc dword ptr [ebp-0x04] /*increment n;*/
            mov eax, [ebp-0x04] /*store n
            's value in eax register*/
            mov [ebp-0x08], eax /*assign value in eax to m*/
            復(fù)制代碼

            注:前綴操作符、后綴操作符與性能之間的聯(lián)系是什么?原文作者沒(méi)有說(shuō)明。所以有了亞歷山大同志 的疑問(wèn)。在此做一下說(shuō)明:當(dāng)應(yīng)用內(nèi)置類型的操作時(shí),前綴和后綴操作符的性能區(qū)別通常可以忽略。然而,對(duì)于用戶自定義類型,后綴操作符的效率要低于前綴操作符,這是因?yàn)樵谶\(yùn)行操作符之間編譯器需要建立一個(gè)臨時(shí)的對(duì)象

            技巧11:盡量消除臨時(shí)對(duì)象

              在一些情況下,C++會(huì)“背著你”創(chuàng)建一些臨時(shí)對(duì)象。一個(gè)臨時(shí)對(duì)象的開(kāi)銷可能很大,因?yàn)樗臉?gòu)造和析構(gòu)函數(shù)肯定會(huì)被調(diào)用。但是,在大多數(shù)情況下,您可以防止臨時(shí)對(duì)象的創(chuàng)建。在下面的例子,一個(gè)臨時(shí)對(duì)象被創(chuàng)建:

            Complex x, y, z;
            x
            =y+z; /* temporary created */

              表達(dá)式y(tǒng)+z;將會(huì)導(dǎo)致一個(gè)Complex類型的臨時(shí)對(duì)象的產(chǎn)生,這個(gè)臨時(shí)對(duì)象保存著相加的結(jié)果。之后,這個(gè)臨時(shí)對(duì)象被賦予x,隨后銷毀。臨時(shí)對(duì)象的生成可以用兩種方式加以避免:

            Complex y,z;
            Complex x
            =y+z; /* initialization instead of assignment */

              在上面的例子中,y和z相加的結(jié)果直接用于對(duì)象x的構(gòu)造,所以就避免了起中介作用的臨時(shí)對(duì)象。或者你可以用+=代替+,同樣可以達(dá)到相同的效果:

            /* instead of x = y+z; */
            x
            =y;
            x
            +=z;

              雖然采用+=的這個(gè)版本不太優(yōu)雅,它只有兩個(gè)成員函數(shù)調(diào)用:賦值操作和+=操作。相較而言,使用+操作符則產(chǎn)生三次成員函數(shù)調(diào)用:臨時(shí)對(duì)象的構(gòu)造、對(duì)于x的拷貝構(gòu)造,以及臨時(shí)對(duì)象的析構(gòu)!

            12 and 13: Object-oriented Design

              雖然C++支持多種非常有用的編程范式,如procedural programming、functional programming、generic programming,以及object-oriented programming。其中object-oriented programming(面向?qū)ο缶幊蹋o(wú)疑是使用最為廣泛和重要的范例。下面的兩個(gè)小技巧將幫助你更好的應(yīng)用面向?qū)ο蟮脑O(shè)計(jì)和實(shí)現(xiàn)。首先,我將解釋一下虛析構(gòu)函數(shù)在類繼承中的重要性。另外一個(gè)小技巧將闡述如何去處理嵌套類:將嵌套類聲明為其包含類的友元。

             

            技巧12:為什么沒(méi)有虛析構(gòu)函數(shù)的類繼承是危險(xiǎn)的?

            如果一個(gè)類的析構(gòu)函數(shù)是非虛的,那么就意味著它不會(huì)作為基類來(lái)使用(這種類就是我們所熟知的“實(shí)體類”)。std::string,std::complex,以及std::vector都是實(shí)體類。為什么不推薦繼承這些類呢?當(dāng)你使用公共繼承時(shí),你就會(huì)在基類與派生類之間創(chuàng)建一種is-a的關(guān)系。因此,基類的指針和引用實(shí)際上可以指向一個(gè)派生的對(duì)象。由于析構(gòu)函數(shù)不是虛的,所以當(dāng)您刪除這樣一個(gè)對(duì)象時(shí),C++將不會(huì)調(diào)用整個(gè)析構(gòu)鏈。例如:

            復(fù)制代碼
            class A
            {
            public:
            ~A() // non virtual
            {
            // ...
            }
            };

            class B: public A /* 不好; A 沒(méi)有虛析構(gòu)函數(shù)*/
            {
            public:
            ~B()
            {
            // ...
            }
            };

            int main()
            {
            A
            * p = new B; /*貌似沒(méi)什么問(wèn)題*/
            delete p;
            /*問(wèn)題出現(xiàn), B的析構(gòu)未被調(diào)用*/
            }
            復(fù)制代碼

              沒(méi)有調(diào)用對(duì)象的析構(gòu)所帶來(lái)的結(jié)果是不確定的。因此,你不應(yīng)該公開(kāi)繼承這樣的類。尤其是,不要繼承STL容器和std::string。

             

            技巧13:將嵌套類聲明為其包含類的友元

              當(dāng)作為其包含類的友元來(lái)聲明一個(gè)嵌套類時(shí),你應(yīng)當(dāng)將友元聲明放于嵌套類聲明的后面,而不是前面:

            復(fù)制代碼
            class A
            {
            private:
            int i;
            public:
            class B /*先定義嵌套類*/
            {
            public:
            B(A
            & a) { a.i=0;};
            };
            friend
            class B;/*友元聲明*/
            };
            復(fù)制代碼

              如果你把友元聲明放置于嵌套類聲明之前,編譯器將丟棄友元聲明,因?yàn)榫幾g器還沒(méi)有見(jiàn)過(guò)它,不知道它是什么玩意兒。

             

            注:關(guān)于嵌套類定義

            A nested class is any class whose declaration occurs within the body of another class or interface. A top level class is a class that is not a nested class.

            一個(gè) class A 如果定義在了另一個(gè) class B 或 interface B 里,那么這個(gè) class A 就是 nested class,class B 或 interface B 則被稱為 enclosing class。至于 class A 是定義在了 class B 或 interface B 的什么地方,例如 method 和 constructor,則是沒(méi)有限制的。

             

            標(biāo)準(zhǔn)模板庫(kù)和通用編程

              標(biāo)準(zhǔn)模板庫(kù)(STL)給C++程序員編寫代碼的方式帶來(lái)了革命性的影響。這樣的代碼重用將生產(chǎn)力水平提升到了更高的水平,節(jié)省了大量的時(shí)間,避免了重復(fù)性的勞動(dòng)。然而,STL是一個(gè)具有特殊術(shù)語(yǔ)和復(fù)雜規(guī)則的、比較全面的框架,如果你想更好的去應(yīng)用它,那么你只能去掌握它,“知己知彼方能百戰(zhàn)不殆”嗎。為了更深入地了解STL某些方面的情況,這大類中將包含6個(gè)小技巧。
              第一個(gè)技巧將介紹一下STL的基本組成和一些關(guān)鍵術(shù)語(yǔ)。接下來(lái)的小技巧則集中于模板定義這一方面。正如你所知,模板是STL容器和算法最基礎(chǔ)的“建筑材料”。接下來(lái)的三個(gè)小技巧將依次描述如何使用標(biāo)準(zhǔn)庫(kù)中應(yīng)用最為廣泛的容器 - vector,學(xué)習(xí)如何在vector中存儲(chǔ)對(duì)象指針,避免常見(jiàn)陷阱,以及如何將vector當(dāng)做一個(gè)內(nèi)置的數(shù)組來(lái)使用。第五個(gè)提示將會(huì)告訴你如何使用vector來(lái)模仿多維數(shù)組。最后的提示將介紹一個(gè)非常重要的問(wèn)題:auto_ptr和STL容器之間的一些問(wèn)題。

             

            技巧14:非常有用的STL術(shù)語(yǔ)
              接下來(lái)所講述的是STL中一些非常關(guān)鍵的條款。也許在你閱讀標(biāo)準(zhǔn)模板庫(kù)(STL)文獻(xiàn)或文檔的時(shí)候,您遇到過(guò)它們。  

              Container 容器
              容器是一個(gè)對(duì)象,它將對(duì)象作為元素來(lái)存儲(chǔ)。通常情況下,它是作為類模板來(lái)實(shí)現(xiàn),其成員函數(shù)包括遍歷元素,存儲(chǔ)元素和刪除元素。std::list和std::vector就是兩種典型的容器類。

              Genericity 泛型
              泛型就是通用,或者說(shuō)是類型獨(dú)立。上面對(duì)于容器類的定義是非常寬松的,因?yàn)樗m用于字符串,數(shù)組,結(jié)構(gòu)體,或者是對(duì)象。一個(gè)真正的容器是不局限于某一種或著某些特定的數(shù)據(jù)類型的。相反,它可以存儲(chǔ)任何內(nèi)置類型或者用戶自定義類型。這樣的容器就被認(rèn)為是通用的。請(qǐng)注意,string只能包含字符。泛型也許是STL的最重要的特征。第三個(gè)技巧將給出函數(shù)對(duì)象的標(biāo)準(zhǔn)基類。因?yàn)楹瘮?shù)對(duì)象是通用編程重的一個(gè)重要部分。在設(shè)計(jì)實(shí)現(xiàn)過(guò)程中,堅(jiān)持標(biāo)準(zhǔn)規(guī)范將會(huì)省去你的很多的困難。
              Algorithm 算法
              算法就是對(duì)一個(gè)對(duì)象序列所采取的某些操作。例如std::sort()排序,std::copy()復(fù)制,和std::remove()刪除。STL中的算法都是將其作為函數(shù)模板來(lái)實(shí)現(xiàn)的,這些函數(shù)的參數(shù)都是對(duì)象迭代器。

              Adaptor 適配器
              適配器是一個(gè)非常特殊的對(duì)象,它可以插入到一個(gè)現(xiàn)有的類或函數(shù)中來(lái)改變它的行為。例如,將一個(gè)特殊的適配器插入到std::sort()算法中,你就可以控制排序是降序還是升序。 STL中定義了多種類型的序列適配器,它可以將一個(gè)容器類變換成一個(gè)具有更嚴(yán)格接口的不同容器。例如,堆棧(stack)就可以由queue<>和適配器來(lái)組成,適配器提供了必要的push()和pop()操作。

              O(h) Big Oh Notation
              O(h)是一個(gè)表示算法性能的特殊符號(hào),在STL規(guī)范當(dāng)中用于表示標(biāo)準(zhǔn)庫(kù)算法和容器操作的最低性能極限。任何其他的實(shí)現(xiàn)可能會(huì)提供更好的性能,但絕不是更壞的。O(h)可以幫助您去評(píng)估一個(gè)算法或者某個(gè)特定類型容器的某個(gè)操作的效率。std::find()算法遍歷序列中的元素,在最壞的情況下,其性能可以表示為:

            T(n) = O(n). /* 線性復(fù)雜度 */

              Iterator 迭代器
              迭代器是一種可以當(dāng)做通用指針來(lái)使用的對(duì)象。迭代器可以用于元素遍歷,元素添加和元素刪除。 STL定義了五個(gè)種主要的迭代器:

            輸入迭代器和輸出迭代器 input iterators and output iterators
            前向迭代器 forward iterators
            雙向迭代器 bidirectional iterators
            隨機(jī)訪問(wèn)迭代器 random access iterators

              請(qǐng)注意,上述迭代器列表并不具有繼承關(guān)系,它只是描述了迭代器種類和接口。下面的迭代器類是上面類的超集。例如,雙向迭代器不僅提供了前向迭代器的所有功能,還包括一些附加功能。這里將對(duì)這些類別做簡(jiǎn)要介紹:

            輸入迭代器允許迭代器前行,并提供只讀訪問(wèn)。
            輸出迭代器允許迭代器前行,并提供只寫訪問(wèn)。
            前向迭代器支持讀取和寫入權(quán)限,但只允許一個(gè)方向上的遍歷。
            雙向迭代器允許用戶在兩個(gè)方向遍歷序列。
            隨機(jī)訪問(wèn)迭代器支持迭代器的隨機(jī)跳躍,以及“指針?biāo)阈g(shù)”操作,例如:

            string::iterator it = s.begin();
            char c = *(it+5); /* assign sixth char to c*/

             

            技巧15:模板定義的位置在哪里?是.cpp文件嗎?

              通常情況下,你會(huì)在.h文件中聲明函數(shù)和類,而將它們的定義放置在一個(gè)單獨(dú)的.cpp文件中。但是在使用模板時(shí),這種習(xí)慣性做法將變得不再有用,因?yàn)楫?dāng)實(shí)例化一個(gè)模板時(shí),編譯器必須看到模板確切的定義,而不僅僅是它的聲明。因此,最好的辦法就是將模板的聲明和定義都放置在同一個(gè).h文件中。這就是為什么所有的STL頭文件都包含模板定義的原因。

              另外一個(gè)方法就是使用關(guān)鍵字“export”!你可以在.h文件中,聲明模板類和模板函數(shù);在.cpp文件中,使用關(guān)鍵字export來(lái)定義具體的模板類對(duì)象和模板函數(shù);然后在其他用戶代碼文件中,包含聲明頭文件后,就可以使用該這些對(duì)象和函數(shù)了。例如:

            復(fù)制代碼
            // output.h - 聲明頭文件
            template<class T> void output (const T& t);

            // out.cpp - 定義代碼文件
            #include <****>
            export template
            <class T> void output (const T& t) {std::cerr << t;}

            //main.cpp:用戶代碼文件

            #include
            "output.h"
            void main() // 使用output()
            {
            output(
            4);
            output(
            "Hello");
            }
            復(fù)制代碼

              某種程度上,這有點(diǎn)類似于為了訪問(wèn)其他編譯單元(如另一代碼文件)中普通類型的變量或?qū)ο蠖捎玫年P(guān)鍵字extern。
              但是,這里還有一個(gè)不得不說(shuō)的問(wèn)題:并非所有的編譯器都支持export關(guān)鍵字(我們最熟悉、最常用的兩款編譯器VS 和 GCC就是不支持export的典型代表)。對(duì)于這種不確定,最好的方法就是采用解決方案一:聲明定義放在一起,雖然這在某種程度上破壞了C++編程的優(yōu)雅

            性。

            ---------------版權(quán)分割線--------以下引自 飛諾網(wǎng)(www.firnow.com)-------------

              分離編譯模式(Separate Compilation Model)允許在一處翻譯單元(Translation Unit)中定義(define)函數(shù)、類型、類對(duì)象等,在另一處翻譯單元引用它們。編譯器(Compiler)處理完所有翻譯單元后,鏈接器(Linker)接下來(lái)處理所有指向 extern 符號(hào)的引用,從而生成單一可執(zhí)行文件。該模式使得 C++ 代碼編寫得稱心而優(yōu)雅。

            然而該模式卻馴不服模板(Template)。標(biāo)準(zhǔn)要求編譯器在實(shí)例化模板時(shí)必須在上下文中可以查看到其定義實(shí)體;而反過(guò)來(lái),在看到實(shí)例化模板之前,編譯器對(duì)模板的定義體是不處理的——原因很簡(jiǎn)單,編譯器怎么會(huì)預(yù)先知道 typename 實(shí)參是什么呢?因此模板的實(shí)例化與定義體必須放到同一翻譯單元中。

            以優(yōu)雅著稱的 C++ 是不能容忍有此“敗家玩意兒”好好活著的。標(biāo)準(zhǔn) C++ 為此制定了“模板分離編譯模式(Separation Model)”及 export 關(guān)鍵字。然而由于 template 語(yǔ)義本身的特殊性使得 export 在表現(xiàn)的時(shí)候性能很次。編譯器不得不像 .net 和 java 所做的那樣,為模板實(shí)體生成一個(gè)“中間偽代碼(IPC,intermediate pseudo - code)”,使得其它翻譯單元在實(shí)例化時(shí)可找到定義體;而在遇到實(shí)例化時(shí),根據(jù)指定的 typename 實(shí)參再將此 IPC 重新編譯一遍,從而達(dá)到“分離編譯”的目的。因此,該標(biāo)準(zhǔn)受到了幾乎所有知名編譯器供應(yīng)商的強(qiáng)烈抵制。
              誰(shuí)支持 export 呢?Comeau C/C++ 和 Intel 7.x 編譯器支持。而以“百分百支持 ISO ”著稱的 VS 和 GCC 卻對(duì)此視而不見(jiàn)。真不知道這兩大編譯器“百分百支持”的是哪個(gè)版本的 ISO。在 VS 2008 中,export 關(guān)鍵字在 IDE 中被標(biāo)藍(lán),表示 VS IDE 認(rèn)識(shí)它,而編譯時(shí),會(huì)用警告友情提示你“不支持該關(guān)鍵字”,而配套的 MSDN 9 中的 C++ keywords 頁(yè)則根本查不到該關(guān)鍵字;而在 VS 2010 中,就沒(méi)那么客氣了,盡管 IDE 中仍然會(huì)將之標(biāo)藍(lán),但卻會(huì)直截了當(dāng)?shù)貓?bào)錯(cuò)。

            ---------------版權(quán)分割線--------以上引自 飛諾網(wǎng)(www.firnow.com)-------------

             

            技巧16:函數(shù)對(duì)象的標(biāo)準(zhǔn)基類

              為了簡(jiǎn)化編寫函數(shù)對(duì)象的過(guò)程,標(biāo)準(zhǔn)庫(kù)提供了兩個(gè)類模板,作為用戶自定義函數(shù)對(duì)象的基類:std::unary_function和std::binary_function。兩者都聲明在頭文件<functional>中。正如名字所顯示的那樣,unary_function被用作是接受一個(gè)參數(shù)的函數(shù)的對(duì)象的基類,而binary_function是接受兩個(gè)參數(shù)的函數(shù)的對(duì)象的基類。這些基類定義如下:

            復(fù)制代碼
            template < class Arg, class Res > struct
            unary_function
            {
            typedef Arg argument_type;
            typedef Res result_type;
            };
            template
            < class Arg, class Arg2, class Res >
            struct binary_function
            {
            typedef Arg first_argument_type;
            typedef Arg2 second_argument_type;
            typedef Res result_type;
            };
            復(fù)制代碼

              這些模板并不提供任何實(shí)質(zhì)性的功能。他們只是確保其派生函數(shù)對(duì)象的參數(shù)和返回值有統(tǒng)一的類型名稱。在下面的例子中,is_vowel繼承自u(píng)nary_function,接受一個(gè)參數(shù):

            復(fù)制代碼
            template < class T >
            class is_vowel: public unary_function< T, bool >
            {
            public:
            bool operator ()(T t) const
            {
            if ((t=='a')||(t=='e')||(t=='i')||(t=='o')||(t=='u'))
            return true;
            return false;
            }
            };
            復(fù)制代碼

             

            技巧17:如何在STL容器中存儲(chǔ)動(dòng)態(tài)分配的對(duì)象?

              假設(shè)你需要在同一容器中存儲(chǔ)不同類型的對(duì)象。通常情況下,您可以通過(guò)存儲(chǔ)儲(chǔ)動(dòng)態(tài)分配對(duì)象的指針來(lái)達(dá)到這一點(diǎn)。然而,除了使用指針外,也可以按照下面的方式將元素插入到容器中:

            class Base {};
            class Derived : public Base{};

            std::vector
            <Base *> v;
            v.push_back(
            new Derived);
            v.push_back(
            new Base);

              如果按照這種方式,那么存儲(chǔ)的對(duì)象只能通過(guò)其容器來(lái)訪問(wèn)。請(qǐng)記住,應(yīng)按照下面的方式刪除分配的對(duì)象:

            delete v[0];
            delete v[
            1];

             

            技巧18:將向量當(dāng)作數(shù)組使用

              假設(shè)你有一個(gè)整型向量vector<int> v,和一個(gè)以int*為參數(shù)的函數(shù)。為了獲得向量v內(nèi)部數(shù)組的地址,并將它傳給函數(shù),你必須使用表達(dá)式&v[0]或者是&*v.front()。舉個(gè)例子:

            復(fù)制代碼
            void func(const int arr[], size_t length );
            int main()
            {
            vector
            <int> vi;
            //.. fill vi
            func(&vi[0], vi.size());
            }
            復(fù)制代碼

              只要你遵守線面的幾條規(guī)則,你用&vi[0]和&*v.front()作為其內(nèi)部數(shù)組地址就會(huì)很安全放心:
            (1)fun()不應(yīng)訪問(wèn)超出數(shù)組范圍的元素。
            (2)向量中的元素必須是連續(xù)的。雖然C++標(biāo)準(zhǔn)中并沒(méi)有做這樣的規(guī)定,但是據(jù)我所知,沒(méi)有一個(gè)vector的實(shí)現(xiàn)不是使用連續(xù)內(nèi)存的。

             

            技巧19:動(dòng)態(tài)多維數(shù)組和向量的恩恩怨怨

              你可以按照以下方式手動(dòng)分配多維數(shù)組:

            復(fù)制代碼
            int (*ppi)[5] = new int[4][5]; /*parentheses required*/
            /*fill array..*/
            ppi[
            0][0] = 65;
            ppi[
            0][1] = 66;
            ppi[
            0][2] = 67;
            //..
            delete [] ppi;
            復(fù)制代碼

              然而,這種編碼風(fēng)格是非常枯燥的,而且容易出錯(cuò)。你必須用圓括號(hào)括起ppi,以確保這個(gè)聲明能被編譯器正確解析;同時(shí)你也必須手動(dòng)地刪除你所分配的內(nèi)存。更糟糕的是,你會(huì)在不經(jīng)意間碰上令人頭疼的緩沖區(qū)溢出。而使用向量的向量來(lái)模擬多維數(shù)組則是一個(gè)更好的選擇:

            復(fù)制代碼
            #include <vector>
            #include
            <iostream>
            using namespace std;
            int main()
            {
            vector
            <vector <int> > v; /*two dimensions*/
            v.push_back(vector
            <int>()); /*create v[0]*/
            v.push_back(vector
            <int>()); /*create v[1]*/
            v[
            0].push_back(15); /*assign v[0][0]*/
            v[
            1].push_back(16); /*assign v[1][0]*/
            }
            復(fù)制代碼

              因?yàn)関ector重載了操作符[],你可以向使用內(nèi)置的二維數(shù)組一樣使用[][]:

            cout << v[0][0];
            cout
            << v[1][0];

              用向量的向量模擬多維數(shù)組主要有兩個(gè)優(yōu)點(diǎn):向量會(huì)自動(dòng)的按照需要來(lái)分配內(nèi)存。其次,它自己負(fù)責(zé)釋放分配的內(nèi)存,而你則不必?fù)?dān)心潛在的內(nèi)存泄漏。

             

            技巧20:為什么你不應(yīng)該在STL容器中存儲(chǔ)auto_ptr對(duì)象?

              在C++標(biāo)準(zhǔn)中,一個(gè)STL元素必須是可以“拷貝構(gòu)造”和“賦值”。這個(gè)條款意味著,對(duì)于一個(gè)給定類,“拷貝”和“賦值”是其非常便利順手的操作。特別是,當(dāng)你將它復(fù)制到目標(biāo)對(duì)象時(shí),原始對(duì)象的狀態(tài)是不會(huì)改變的。

              但是,這是不適用auto_ptr的。因?yàn)閍uto_ptr的從一個(gè)拷貝到另一個(gè)或賦值到另一個(gè)對(duì)象時(shí)會(huì)使得原始對(duì)象產(chǎn)生預(yù)期變動(dòng)之外的變化。具體說(shuō)來(lái)就是,會(huì)將原來(lái)的對(duì)象的指針轉(zhuǎn)移到目標(biāo)對(duì)象上,從而使原來(lái)的指針變?yōu)榭罩羔槪囅胍幌拢绻障旅娲a所示來(lái)做,會(huì)出現(xiàn)什么結(jié)果呢:

            std::vector <auto_ptr <Foo> > vf;/*a vector of auto_ptr's*/
            // ..fill vf
            int g()
            {
            std::auto_ptr
            <Foo> temp=vf[0]; /*vf[0] becomes null*/
            }

              當(dāng)temp被初始化時(shí),vf[0]的指針變成空。任何對(duì)該元素的調(diào)用都將導(dǎo)致程序的運(yùn)行崩潰。在您從容器中復(fù)制元素時(shí),這種情況極有可能會(huì)發(fā)生。注意,即使您的代碼中沒(méi)有執(zhí)行任何顯式的拷貝操作或賦值操作,許多算法(例如std::swap()和std::random_shuffle()等)都會(huì)創(chuàng)建一個(gè)或多個(gè)元素的臨時(shí)副本。此外,該容器的某些成員函數(shù)也會(huì)創(chuàng)建一個(gè)或多個(gè)元素的臨時(shí)副本,這就會(huì)抵消原有的元素指針。以致任何對(duì)容器中元素的后續(xù)操作都將帶來(lái)的不確定的后果。

              可能Visual C++用戶會(huì)說(shuō),我在STL容器中使用auto_ptr時(shí),從來(lái)沒(méi)有遇到過(guò)任何問(wèn)題。這是因?yàn)樵赩isual C++中auto_ptr的實(shí)現(xiàn)已經(jīng)過(guò)時(shí),而且依賴在一個(gè)過(guò)時(shí)規(guī)范上。如果廠商決定趕上當(dāng)前的最新ANSI/ISO C++標(biāo)準(zhǔn),并相應(yīng)地改變它的標(biāo)準(zhǔn)庫(kù),在STL容器中使用auto_ptr將會(huì)導(dǎo)致嚴(yán)重故障。

              總結(jié)來(lái)說(shuō),你是不應(yīng)該在STL容器中使用auto_ptr的。你可以使用普通指針或其他智能指針類,但絕不是auto_ptr指針。

             

            //------------------------------------------

            <<任何時(shí)候都適用的20個(gè)C++技巧>>這個(gè)小系列到此就結(jié)束了,雖然關(guān)于C++的技巧還很多,還值得我們?nèi)タ偨Y(jié)。如果遇到,我會(huì)第一時(shí)間拿出來(lái)與大家分享! 謝謝各位博友!!

             

            作者: 凌云健筆

            出處:http://www.cnblogs.com/lijian2010/

            版權(quán):本文版權(quán)歸作者和博客園共有
            轉(zhuǎn)載:歡迎轉(zhuǎn)載,為了保存作者的創(chuàng)作熱情,請(qǐng)按要求【轉(zhuǎn)載】
            要求:未經(jīng)作者同意,必須保留此段聲明;必須在文章中給出原文連接;否則必究法律責(zé)任

             

            posted on 2012-06-29 17:29 Daywei 閱讀(447) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++之父力作學(xué)習(xí)筆記

            <2012年6月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            1234567

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿

            隨筆分類

            隨筆檔案

            文章檔案

            牛人博客

            搜索

            積分與排名

            最新評(píng)論

            閱讀排行榜

            国产精品VIDEOSSEX久久发布| 亚洲国产小视频精品久久久三级| 国产精品gz久久久| www.久久热.com| 99久久99这里只有免费费精品 | 亚洲精品无码久久久久去q| 性做久久久久久久久久久| 国产高潮国产高潮久久久91 | 国产福利电影一区二区三区,免费久久久久久久精 | 久久精品日日躁夜夜躁欧美| 亚洲国产成人精品久久久国产成人一区二区三区综 | 88久久精品无码一区二区毛片| 久久er国产精品免费观看2| 久久精品国产精品国产精品污| 久久se精品一区精品二区| 亚洲国产精品一区二区久久| 国产免费福利体检区久久| 蜜臀久久99精品久久久久久| 欧美成人免费观看久久| 欧美国产成人久久精品| 久久水蜜桃亚洲av无码精品麻豆| 99精品国产在热久久无毒不卡| 国产福利电影一区二区三区久久老子无码午夜伦不 | 伊人久久五月天| 久久亚洲精品成人AV| 97久久国产亚洲精品超碰热| 国产成人香蕉久久久久| 久久人人爽人人爽人人片AV高清 | 77777亚洲午夜久久多喷| 国产精品免费看久久久香蕉| 久久综合视频网| 国产精品久久国产精品99盘 | 色婷婷久久综合中文久久一本| 久久国产欧美日韩精品免费| 午夜天堂精品久久久久| 青青草原综合久久| 亚洲乱码日产精品a级毛片久久| 欧美亚洲色综久久精品国产| 久久99精品国产99久久6| 性欧美丰满熟妇XXXX性久久久 | 一本久久a久久精品亚洲|