• <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>

            longshanks

              C++博客 :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
              14 Posts :: 0 Stories :: 214 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(10)

            我參與的團(tuán)隊(duì)

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            C++的營(yíng)養(yǎng)

            莫華楓
                上一篇《C++的營(yíng)養(yǎng)——RAII》中介紹了RAII,以及如何在C#中實(shí)現(xiàn)。這次介紹另一個(gè)重要的基礎(chǔ)技術(shù)——swap手法。

            swap手法

                swap手法不應(yīng)當(dāng)是C++獨(dú)有的技術(shù),很多語(yǔ)言都可以實(shí)現(xiàn),并且從中得到好處。只是C++存在的一些缺陷迫使大牛們發(fā)掘,并開(kāi)始重視這種有用的手法。這 個(gè)原本被用來(lái)解決C++的資源安全和異常保證問(wèn)題的技術(shù)在使用中逐步體現(xiàn)出越來(lái)越多的應(yīng)用,有助于我們編寫(xiě)更加簡(jiǎn)潔、優(yōu)雅和高效的代碼。
                接下來(lái),我們先來(lái)和swap打個(gè)招呼。然后看看在C#里如何玩出swap。最后展示swap手法的幾種應(yīng)用,從中我們將看到它是如何的可愛(ài)。
                假設(shè),我要做一個(gè)類,實(shí)現(xiàn)統(tǒng)計(jì)并保存一個(gè)字符串中字母的出現(xiàn)次數(shù),以及總的字母和數(shù)字的個(gè)數(shù)。
                    class CountStr
                    
            {
                    
            public:
                        
            explicit CountStr(std::string const& val)
                            :m_str(val), m_nLetter(
            0), m_nNumber(0{
                            do_count(val);
                        }

                        CountStr(CountStr 
            const& cs)
                            :m_str(cs.m_str), m_counts(cs.m_counts)
                            , m_nLetter(cs.m_nLetter), m_nNumber(cs.m_nNumber)
                        
            {}
                           
            void swap(CountStr& cs) {
                               std::swap(m_str, cs.m_str);
                               m_counts.swap(m_str);
                               std::swap(m_nLetter, cs.m_nLetter);
                               std::swap(m_nNumber, cs.m_nNumber);
                           }

                    
            private:
                        std::
            string m_str;
                        std::map
            <charint> m_counts;
                        
            int m_nLetter;
                        
            int m_nNumber;
                    }
                在類CountStr中,定義了swap成員函數(shù)。swap接受一個(gè)CountStr&類型的參數(shù)。在函數(shù)中,我們可以看到一組函數(shù)調(diào)用,每一個(gè) 對(duì)應(yīng)一個(gè)數(shù)據(jù)成員,其任務(wù)是將相對(duì)應(yīng)的數(shù)據(jù)成員的內(nèi)容相互交換。此處,我使用了兩種調(diào)用,一種是使用std::swap()標(biāo)準(zhǔn)函數(shù),另一種是通過(guò) swap成員函數(shù)執(zhí)行這個(gè)交換。一般情況下,std::swap()通過(guò)一個(gè)臨時(shí)變量實(shí)現(xiàn)對(duì)象的內(nèi)容交換。但對(duì)于string、map等非平凡的對(duì)象,這 種交換會(huì)引發(fā)至少三次深拷貝,其復(fù)雜度將是O(3n)的,性能極差。因此,標(biāo)準(zhǔn)庫(kù)為這些類定義了swap成員函數(shù),通過(guò)成員函數(shù)可以實(shí)現(xiàn)O(1)的交換操 作。同時(shí)將std::swap()針對(duì)這些擁有swap()成員函數(shù)的標(biāo)準(zhǔn)容器特化,使其可以直接使用swap()成員函數(shù),而避免性能損失。但是,對(duì)于 那些擁有swap()成員,但沒(méi)有被特化的用戶定義,或第三方的類,則不應(yīng)使用std::swap(),而改用swap()成員函數(shù)。所以,一般情況下, 為了避免混淆,對(duì)于擁有swap()成員函數(shù)的類,調(diào)用swap(),否則調(diào)用標(biāo)準(zhǔn)std::swap()函數(shù)。
                順便提一下,在未來(lái)的C++0x中,由于引入了concept機(jī)制,可以允許一個(gè)函數(shù)模板自動(dòng)識(shí)別出所有“具有swap()成員”的類型,并使用相應(yīng)的特化版本。這樣便只需使用std::swap(),而不必考慮是什么樣的類型了。
                言歸正傳。這里,swap()成員函數(shù)有兩個(gè)要求,其一是復(fù)雜度為O(1),其二是具備無(wú)拋擲的異常保證。前者對(duì)于性能而言至關(guān)重要,否則swap操作將 會(huì)由于性能問(wèn)題而無(wú)法在實(shí)際項(xiàng)目中使用。對(duì)于后者,是確保強(qiáng)異常保證(commit or rollback語(yǔ)義)的基石。要達(dá)到這兩個(gè)要求,有幾個(gè)關(guān)鍵要點(diǎn):首先,對(duì)于類型為內(nèi)置類型或小型POD(8~16字節(jié)以內(nèi))的成員數(shù)據(jù),可以直接使用 std::swap();其次,對(duì)于非平凡的類型(擁有資源引用,復(fù)制構(gòu)造和賦值操作會(huì)引發(fā)深拷貝),并且擁有符合上述要求的swap()成員函數(shù)的,直 接使用swap()成員函數(shù);最后,其余的類型,則保有其指針,或智能指針,以確保滿足上述兩個(gè)要求。
                聽(tīng)上去有些復(fù)雜,但在實(shí)際開(kāi)發(fā)中做到并不難。首先,盡量使用標(biāo)準(zhǔn)庫(kù)容器,因?yàn)闃?biāo)準(zhǔn)庫(kù)容器都擁有滿足兩個(gè)條件的swap()成員。其次,在編寫(xiě)的每一個(gè)類中 實(shí)現(xiàn)滿足兩個(gè)條件的swap()成員。最后,對(duì)于那些不具備swap()成員函數(shù)的第三方類型,則使用指針,最好是智能指針。(也就是Sutter所謂的 PImpl手法)。只要堅(jiān)持這些方針,必能收到很好的效果。
                下面,就來(lái)看一下這個(gè)swap()的第一個(gè)妙用。假設(shè),這個(gè)類需要復(fù)制。通常可以通過(guò)operator=操作符,或者copy(或其他有明確的復(fù)制含義 的)成員函數(shù)實(shí)現(xiàn),這兩者實(shí)際上是等價(jià)的,只是形式不同而已。這里選擇operator=,因?yàn)樗容^C++:)。
                最直白的實(shí)現(xiàn)方式是這樣:
                    class CountStr
                    
            {
                    
            public:
                        ...
                        CountStr
            & operator=(CountStr& val) {
                            m_str
            =val.m_str;
                            m_counts
            =val.m_counts;
                            m_nLetter
            =val.m_nLetter;
                            m_nNumber
            =val.m_nNumber;
                        }

                        ...
                    }
                很簡(jiǎn)單,但是不安全,或者說(shuō)沒(méi)有滿足異常保證。
                先解釋一下異常保證。異常保證有三個(gè)級(jí)別:基本保證、強(qiáng)異常保證和無(wú)拋擲保證。基本保證是指異常拋出時(shí),程序的各個(gè)部分應(yīng)當(dāng)處于有效狀態(tài),不能有資源泄 漏。這個(gè)級(jí)別可以輕而易舉地利用RAII確保,這在前一篇已經(jīng)展示過(guò)了。強(qiáng)異常保證則更加嚴(yán)格,要求異常拋出后,程序非但要滿足基本保證,其各個(gè)部分的數(shù) 據(jù)應(yīng)保持原狀。也就是要滿足“Commit or Rollback”語(yǔ)義,熟悉數(shù)據(jù)庫(kù)的人,可以聯(lián)想一下Transaction的行為。而無(wú)拋擲保證要求函數(shù)在任何情況下都不會(huì)拋出異常。無(wú)拋擲保證不是 說(shuō)用一個(gè)catch(...)或throw()把異常統(tǒng)統(tǒng)吞掉。而是說(shuō)在無(wú)拋擲保證的函數(shù)中的任何操作,都不會(huì)拋出異常。能滿足無(wú)拋擲保證的操作還是很多 的,比如內(nèi)置POD類型(int、指針等等)的復(fù)制,swap手法便以此為基礎(chǔ)。(多說(shuō)一句,用catch(...)吞掉異常來(lái)確保無(wú)拋擲并非絕對(duì)不行, 在特定情況下,還是可以偶爾一用。不過(guò)這等爛事也只能在西構(gòu)函數(shù)中進(jìn)行,而且也只有在迫不得已的情況下用那么一下)。
                如果這四個(gè)賦值操作 中,任意一個(gè)拋出異常,便會(huì)退出這個(gè)函數(shù)(操作符)。此時(shí),至少有一個(gè)成員數(shù)據(jù)沒(méi)有正確修改,而其他的則全部或部分地發(fā)生改變。于是,一部分成員數(shù)據(jù)是新 的,另一部分是舊的,甚至還有一些是不完全的。這在軟件中往往會(huì)引發(fā)很多令人苦惱的bug。無(wú)論如何,此時(shí)應(yīng)當(dāng)運(yùn)用強(qiáng)異常保證,使得數(shù)據(jù)要么是新的值,要 么沒(méi)有改變。那么如何獲得強(qiáng)異常保證?在swap()的幫助下,驚人的簡(jiǎn)單:
                    class CountStr
                    
            {
                    
            public:
                        ...
                        CountStr
            & operator=(CountStr& val) {
                            swap(CountStr(val)); 
            // 或者CountStr(val).swap(*this);
                            raturn *this;                    
                        }

                        ...
                    }
                我想世上沒(méi)有比這等代碼更加漂亮的了吧!不僅僅具有簡(jiǎn)潔動(dòng)人的外表,而且充滿了豐富的內(nèi)涵。這就叫優(yōu)雅。不過(guò),優(yōu)雅之下還需要一些解釋。在這兩個(gè)版本中, 都是先用復(fù)制構(gòu)造創(chuàng)建一個(gè)臨時(shí)對(duì)象,這個(gè)臨時(shí)對(duì)象同傳入的參數(shù)對(duì)象擁有相同的值。然后用swap()成員函數(shù)將this對(duì)象的內(nèi)容與臨時(shí)對(duì)象交換。于是, this對(duì)象擁有了臨時(shí)對(duì)象的值,也就是與傳入的實(shí)參對(duì)象具有相同的值(復(fù)制)。當(dāng)退出函數(shù)的時(shí)候,臨時(shí)對(duì)象銷毀,自然而然地釋放了this對(duì)象原先的資 源(前提是CountStr類實(shí)現(xiàn)了RAII)。
                那么拋出異常的情況又是怎樣的呢?
                先來(lái)看看operator=里執(zhí)行了哪些步驟,并考察這些步驟的異常拋擲的情況。如果將代碼改寫(xiě)成另一個(gè)等價(jià)的形式,就很容易理解了:
                        CountStr& operator=(CountStr& val) {
                            CountStr t_(val);    
            //此處可能拋出異常,但只有t_的值發(fā)生變化
                            t_.swap(*this);       //由于swap擁有無(wú)拋擲保證,所以不會(huì)拋出異常
                            return *this
                        }
                在構(gòu)造臨時(shí)對(duì)象的時(shí)候,可能會(huì)拋出異常,因?yàn)榇藭r(shí)執(zhí)行了數(shù)據(jù)的復(fù)制和構(gòu)造。請(qǐng)注意,這時(shí)候this對(duì)象的內(nèi)容沒(méi)有改變。如果此時(shí)拋出異常,數(shù)據(jù)發(fā)生改變的 只有t_,this對(duì)象并未受到影響。而隨著棧清理,t_也將被析構(gòu),在RAII的作用下,t_所占用的資源也會(huì)依次釋放。而下一步,swap()成員的 調(diào)用,則是無(wú)拋擲保證的,不會(huì)拋出異常,this的內(nèi)容可以得到充分地、原子地交換,不會(huì)發(fā)生數(shù)據(jù)值修改一半的情況。
                在C#中,實(shí)現(xiàn)swap非常容易,甚至比C++更容易。因?yàn)樵贑#中,大部分對(duì)象都在堆上,代碼中定義的所謂對(duì)象實(shí)際上是引用。對(duì)于引用的賦值操作是無(wú)拋擲的,因此在C#中可以采用同C++幾乎一樣的代碼實(shí)現(xiàn)swap:
                    class CountStr
                    
            {
                        
            public CountStr(string val) {
                            m_str
            =val;
                            m_nLetter
            =0;
                            m_nNumber
            =0;
                            do_count(val);
                        }

                        
            public CountStr(CountStr cs) {
                            m_str
            =new string(cs.m_str);
                            m_counts
            =new Dictionary<charint>(cs.m_counts);
                            m_nLetter
            =cs.m_nLetter;
                            m_nNumber
            =cs.m_nNumber
                        }


                          
            public void swap(CountStr& cs) {
                               utility.swap(
            ref m_str, ref cs.m_str);
                               utility.swap(
            ref m_counts, ref cs.m_counts);
                               utility.swap(
            ref m_nLetter, ref cs.m_nLetter);
                               utility.swap(
            ref m_nNumber, ref cs.m_nNumber);
                          }

                        
            public void copy(CountStr& cs) {
                            
            this.swap(new CountStr(cs));
                        }


                        
            private string m_str;
                        
            private Dictionary<charint> m_counts;
                        
            private int m_nLetter;
                        
            private int m_nNumber;
                    }
                這里utility.swap()是一個(gè)泛型函數(shù),作用是交換兩個(gè)參數(shù):
                    class utility
                    
            {
                        
            public static void swap<T>(ref T lhs, ref T rhs) {
                            T t_
            =lhs;
                            lhs
            =rhs;
                            rhs
            =t_;
                        }

                    }
                如果類有關(guān)鍵性的資源需要釋放,那么可以實(shí)現(xiàn)IDisposable接口,然后在copy()中使用using:
                        public void copy(CountStr& cs) {
                            
            using(CountStr t_=new CountStr(cs))
                                
            {
                                    t_.swap(
            this);
                                }

                        }
                如此,對(duì)象原有的數(shù)據(jù)和資源被交換到臨時(shí)對(duì)象t_中之后,在退出using作用域的時(shí)候,會(huì)立即得到釋放。這是RAII的一個(gè)應(yīng)用,詳細(xì)內(nèi)容參見(jiàn)本系列的前一篇《C++的營(yíng)養(yǎng)——RAII》。
                swap的基本作用是維持強(qiáng)異常保證語(yǔ)義。但是,作為一種基礎(chǔ)性的技術(shù),它還可以擁有更多的用途。下面介紹幾種主要的應(yīng)用,為了節(jié)省篇幅,案例直接使用C#,不再給出C++的代碼。
                在我們的開(kāi)發(fā)過(guò)程中,有時(shí)需要是一些對(duì)象復(fù)位,即回復(fù)對(duì)象的初始狀態(tài)。一般情況下,我們會(huì)在類中增加一個(gè)reset()之類的成員,在這個(gè)函數(shù)中釋放資源,恢復(fù)各成員數(shù)據(jù)的初值。但是,在擁有swap的情況下,這種操作變得非常容易:
                    class X
                    
            {
                        
            public X() {
                            ... 
            //初始化對(duì)象
                        }

                        
            public X(int v) {
                            ... 
            //以v初始化對(duì)象
                        }

                        
            public void swap(X val) {...}
                        
            public void reset() {
                            
            this.swap(new X());
                        }

                        ...
                    }
                reset()用X的默認(rèn)構(gòu)造函數(shù)創(chuàng)建了一個(gè)臨時(shí)對(duì)象,將其內(nèi)容與this交換,this的內(nèi)容便成為了初始值。重要的是,這個(gè)成員函數(shù)也是強(qiáng)異常保證的。如果需要通過(guò)一些參數(shù)復(fù)位,那么同樣可以做到:
                    class X
                    
            {
                        ...
                        
            public void reset(int v) {
                            
            this.swap(new X(v));
                        }

                        ...
                    }
                有時(shí)甚至可以不需要reset這個(gè)成員,而直接在代碼中使用swap復(fù)位一個(gè)對(duì)象:
                    X x=new X();
                    ... 
            //對(duì)x的操作,改變了內(nèi)容
                    x.swap(new X()); //復(fù)位了
                如果X有資源需要釋放,那么只需實(shí)現(xiàn)IDispose,然后使用using:
                    class X : IDisposable
                    
            {
                        ...
                        
            public void reset() {
                            
            using(X t=new X())
                            
            {
                                
            this.swap(t);
                            }

                        }

                        
            public void Dispose() {...}
                        ...
                    }
                上面這些應(yīng)用都有一個(gè)共同點(diǎn),即重新初始化一個(gè)對(duì)象,使其恢復(fù)到一個(gè)初始狀態(tài)。下面的應(yīng)用,則反其道而行之,將一個(gè)對(duì)象切換到另一個(gè)狀態(tài)。
                有時(shí),我們會(huì)做一些類,在構(gòu)造函數(shù)中執(zhí)行一些復(fù)雜的操作,比如解析一個(gè)文本文件,然后向外公布解析后的結(jié)果。之后,我們需要在這個(gè)對(duì)象上load另一個(gè)文 件,那么通常都寫(xiě)一個(gè)load成員函數(shù),先釋放掉原先占用的資源,然后再加載新的文件。如果有了swap,那么這個(gè)load函數(shù)同樣極其簡(jiǎn)單:
                    class Y : IDisposable
                    
            {
                        
            public Y(string filename) {
                            ... 
            //打開(kāi)文件,執(zhí)行解析
                        }

                        
            public void swap(Y val) {...}
                        
            public load(string filename) {
                            
            using(Y t=new Y(filename))
                            
            {
                                
            this.swap(t);
                            }

                        }

                        
            public void Dispose() {
                            ... 
            //關(guān)閉文件,釋放資源
                        }

                    }
                還有一種情況,有一些類,通過(guò)一些數(shù)據(jù)創(chuàng)建,創(chuàng)建之后在絕大多數(shù)的情況下都是只讀的,但偶爾會(huì)需要改變其內(nèi)部數(shù)據(jù)。為了代碼的可靠性,我們可以把類寫(xiě)成只讀的。但是如何修改其內(nèi)部的數(shù)據(jù)呢?也可以通過(guò)swap:
                    class Z
                    
            {
                        
            public Z(int a, float b) {
                            m_a
            =a;
                            m_b
            =b;
                        }

                        
            public void swap(Z val) {...}
                        
            public int a get{return m_a;}}
                        
            public float b get{return m_b;}}
                        
            private int m_a;
                        
            private float m_b;
                    }


                    Z z
            =new Z(34.5);
                    z.swap(
            new Z(5, 5.4)); //z的值已修改
                這樣便可避免對(duì)Z的實(shí)例的隨意修改。但是,這種修改方式會(huì)造成性能損失,特別是數(shù)據(jù)成員存在非O(1)復(fù)制的情況下(如有字符串、數(shù)組等),只有在修改偶爾發(fā)生的情況下才能使用。
                有些類,構(gòu)造函數(shù)需要一些數(shù)據(jù)初始化對(duì)象,并且會(huì)創(chuàng)建的過(guò)程中會(huì)驗(yàn)證其有效性,和執(zhí)行一些計(jì)算。也就是構(gòu)造函數(shù)存在一定的數(shù)據(jù)邏輯。如果需要修改對(duì)象的某 些值,會(huì)牽涉到相應(yīng)的復(fù)雜數(shù)據(jù)邏輯。通常都是把這些邏輯獨(dú)立在private成員函數(shù)中,由構(gòu)造函數(shù)和數(shù)據(jù)修改操作共享。這樣的做法往往不能帶來(lái)強(qiáng)異常保 證,在構(gòu)造函數(shù)里的數(shù)據(jù)驗(yàn)證往往會(huì)拋出異常。因此,如果使用swap,便可以消除這類問(wèn)題,并且使代碼簡(jiǎn)化:
                    class A
                    
            {
                        
            public A(int a, string b, Rectangle c) {
                            ... 
            //數(shù)據(jù)邏輯、計(jì)算等
                        }

                        
            public int a {
                            
            setthis.swap(new A(value, m_b, m_c));}
                        }

                        
            public string b {
                            
            setthis.swap(new A(m_a, value, m_c));}
                        }

                        
            public Rectangle c {
                            
            setthis.swap(new A(m_a, m_b, value));}
                        }

                        ...
                   }
                當(dāng)然,也可以在類外直接進(jìn)行這樣的數(shù)據(jù)設(shè)置:
                    A a=new A(2"zzz", Rectangle(1,110,10));
                    a.swap(
            new A(3, "zzz", Rectangle(1,1, 10,10)));
                這種用法可以用于某些只保存對(duì)構(gòu)造函數(shù)參數(shù)的計(jì)算結(jié)果,而不需要保存這些參數(shù)的類(m_a,m_b,m_c都不需要了),只是使用上過(guò)于瑣碎。
                所有這些與對(duì)象狀態(tài)設(shè)置有關(guān)的swap用法,都集中表現(xiàn)了一個(gè)特性,即使得我們可以將對(duì)象的初始化代碼集中在構(gòu)造函數(shù)中,數(shù)據(jù)和資源清理的代碼集中在 Dispose()中。這種做法可以大大提高代碼的可維護(hù)性。如果一個(gè)軟件項(xiàng)目中,每個(gè)類都實(shí)現(xiàn)swap和復(fù)制構(gòu)造函數(shù)(除非該類不允許復(fù)制),并盡可能 集中數(shù)據(jù)邏輯代碼,那么會(huì)使得代碼質(zhì)量有答復(fù)的提高。
                在上一篇《C++的營(yíng)養(yǎng)——RAII》中,我提到守衛(wèi)一個(gè)結(jié)構(gòu)復(fù)雜的類:在代碼中修改一個(gè)對(duì)象,然后再回復(fù)原來(lái)的狀態(tài)。如果單純手工地保存對(duì)象數(shù)據(jù),通常 很困難(有時(shí)甚至是不可能的),而且也難以維持異常安全性(強(qiáng)異常保證)。但是如果使用了swap,那么將會(huì)易如反掌:
                    void ScopeObject(MyCls obj) {
                        
            using(MyCls t_=new MyCls(obj))
                        
            {
                            ... 
            //操作obj,改變其狀態(tài)或數(shù)據(jù)
                            obj.swap(t_); //恢復(fù)原來(lái)的狀態(tài)
                        }

                    }
                當(dāng)然,也可以直接使用t_執(zhí)行操作,這就不需要執(zhí)行swap。在一般情況下兩者是等價(jià)的。但是,在某些特殊情況下,比如類持有特殊資源,或者obj是并發(fā) 中的共享對(duì)象的時(shí)候,兩種方法有可能不等價(jià)。swap方案使用上更全面些。總的來(lái)說(shuō)相差不多,放在這里僅供參考。
                作為更進(jìn)一步的發(fā)展,可以構(gòu)造一個(gè)ISwapable泛型接口:
                    interface ISwapable<T>
                    
            {
                        
            void swap(T v);
                    }
                對(duì)于需要實(shí)現(xiàn)swap手法的類,實(shí)現(xiàn)這個(gè)接口:
                    class B : ISwapable<B>
                    
            {
                        
            public B() {...}
                        
            public void swap(B v) {...}
                        ...
                    }
                這將會(huì)帶來(lái)一個(gè)好處,通過(guò)泛型算法實(shí)現(xiàn)某些特定的操作:
                    class utility
                    
            {
                        
            public static void reset<T>(T obj)
                            
            where T : ISwapable
                            
            where T : new()
                        
            {
                            obj.swap(
            new T());
                        }

                    }
                這樣便無(wú)須為每一個(gè)類編寫(xiě)reset成員函數(shù),只需這一個(gè)泛型算法即可:
                    X x;
                    Y y;
                    utility.reset(x);
                    utility.reset(y);
                    ...
                swap手法可能在存在其他諸多應(yīng)用,在編碼的時(shí)候可以不斷地發(fā)掘。只需要抓住一個(gè)原則:swap可以無(wú)拋擲,簡(jiǎn)潔地修改一個(gè)對(duì)象的值。swap所帶來(lái)的 一個(gè)問(wèn)題主要是性能方面。swap通常伴隨著臨時(shí)對(duì)象的構(gòu)造,多數(shù)情況下,這種構(gòu)造不會(huì)引發(fā)更多的性能損失,但在某些數(shù)據(jù)修改的應(yīng)用中,會(huì)比直接的數(shù)據(jù)修 改損失更多的性能。如何取舍,需要根據(jù)具體情況分析和權(quán)衡。總的來(lái)說(shuō),swap手法所帶來(lái)的好處是顯而易見(jiàn)的,特別是強(qiáng)異常保證,往往是至關(guān)重要的。而諸 如簡(jiǎn)化代碼等的作用,則無(wú)需多言,一用便知。
                或許swap手法非常基礎(chǔ),非常細(xì)小,而且很多人不用swap也過(guò)來(lái)了。但是,聚沙成塔,每一處細(xì)小的優(yōu)化,積累起來(lái)則是巨大的進(jìn)步。還是劉皇叔說(shuō)得好:“勿以善小而不為,勿以惡小而為之”。
            posted on 2008-02-26 15:16 longshanks 閱讀(3907) 評(píng)論(3)  編輯 收藏 引用

            Feedback

            # re: C++的營(yíng)養(yǎng)——swap手法[未登錄](méi) 2008-02-26 16:41 heroboy
            map重載了std::swap,所以一般情況下都可以用std::swap,沒(méi)有必要用成員函數(shù)。  回復(fù)  更多評(píng)論
              

            # re: C++的營(yíng)養(yǎng)——swap手法[未登錄](méi) 2008-02-26 16:56 heroboy
            swap就做swap的功能吧,擴(kuò)展太多功能的話,代碼不容易讀懂。
            c#其實(shí)沒(méi)必要用ISwapable接口,用反射的話每個(gè)對(duì)象都可以swap。  回復(fù)  更多評(píng)論
              

            # re: C++的營(yíng)養(yǎng)——swap手法 2008-03-09 16:47 DK_jims
            C# 在中間語(yǔ)言上,每個(gè)類都有個(gè)tostirng的~ 還要RTTI?  回復(fù)  更多評(píng)論
              


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久精品国产乱子伦| 亚洲AV伊人久久青青草原| 久久久久亚洲AV片无码下载蜜桃| 久久伊人精品一区二区三区| 久久午夜夜伦鲁鲁片免费无码影视| 少妇高潮惨叫久久久久久| 久久精品中文字幕久久| 国产69精品久久久久观看软件| 久久久久亚洲AV无码麻豆| 久久人人爽人人澡人人高潮AV| 无码国内精品久久人妻蜜桃| 国产ww久久久久久久久久| 国产69精品久久久久9999APGF | 蜜桃麻豆www久久| 偷窥少妇久久久久久久久| 久久久久久亚洲精品成人| 久久午夜电影网| 久久久亚洲欧洲日产国码二区 | 亚洲欧美成人久久综合中文网 | 久久免费99精品国产自在现线| 精品无码久久久久久尤物| 精品无码久久久久国产动漫3d | 三上悠亚久久精品| 久久天天婷婷五月俺也去| 久久精品国产亚洲一区二区三区| 97精品伊人久久大香线蕉app| 色综合久久久久综合体桃花网| 香蕉久久久久久狠狠色| 午夜视频久久久久一区 | 中文国产成人精品久久不卡 | 久久久精品国产亚洲成人满18免费网站| 久久久久人妻精品一区二区三区| 久久精品国产日本波多野结衣| 久久WWW免费人成—看片| 久久精品国产精品亚洲艾草网美妙| 国产一久久香蕉国产线看观看| 久久精品亚洲精品国产色婷 | 无码国内精品久久人妻蜜桃| 欧美噜噜久久久XXX| 久久夜色精品国产网站| 99re这里只有精品热久久|