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

            Note of Justin

            關(guān)于工作和讀書的筆記

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

            留言簿(14)

            搜索

            •  

            積分與排名

            • 積分 - 52710
            • 排名 - 433

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            [原創(chuàng)文章歡迎轉(zhuǎn)載,但請(qǐng)保留作者信息]
            Justin 于 2009-11-12

            第十項(xiàng)所言無(wú)他,就是要記得定義拷貝運(yùn)算符時(shí)要返回對(duì)象自身的引用(*this)。原因很簡(jiǎn)單,你會(huì)有連著用=號(hào)的時(shí)候(a=b=c),如果不返回對(duì)象的引用這一串賦值式子就無(wú)法傳遞下去。

            Item11說(shuō)的也是拷貝運(yùn)算符,不過(guò)側(cè)重點(diǎn)在使用=號(hào)對(duì)自身賦值的特殊情況(a=a)。再繼續(xù)下去之前Scott先是舉了個(gè)很傻的例子:一個(gè)賦值函數(shù)

            class ?Bitmap? { // ..}

            class ?Widget? {
            // ..
            private :
            ???Bitmap?
            * pb;
            }

            ???
            Widget
            &
            Widget::
            operator = ( const ?Widget & ?rhs)
            {
            ???delete?pb;
            ???pb?
            = ? new ?Bitmap( * rhs.pb);
            ???
            return ? * this ;
            }

            這樣的一個(gè)傻傻賦值函數(shù)有兩個(gè)問(wèn)題:
            ?? 1. 在自賦值的時(shí)候是要出事的。(在自賦值的時(shí)候:pb被釋放之后,緊接著就又被當(dāng)作右值來(lái)構(gòu)造新的對(duì)象……)
            ?? 2. 在發(fā)生異常的時(shí)候也是要出事的。(設(shè)想如果在new的過(guò)程中出錯(cuò)然后拋出異常,結(jié)果就是我們的pb成了野指針:它指向一個(gè)已經(jīng)delete了的內(nèi)存空間,你無(wú)法再次delete它,也不能讀,因?yàn)槟悴恢滥阕x到的是什么@#¥%)

            于是就有了以下應(yīng)付自賦值的策略:

            1. 在函數(shù)入口檢查是否屬于自拷貝(例如:檢查指針是否指向同一片內(nèi)存),如果是,啥也不干直接返回。否則屬于正常情況的拷貝。偷個(gè)懶,用書上的術(shù)語(yǔ):這樣解決了self-assignment-unsafe的問(wèn)題,但是沒(méi)能避免exception-unsafe。
            2. 第二種方法比較簡(jiǎn)單,只是整理一下指令的順序。但是卻同時(shí)解決了自賦值和拋出異常帶來(lái)的問(wèn)題。繼續(xù)無(wú)恥的抄寫代碼一段:
              Widget&
              Widget::
              operator=(const?Widget&?rhs)
              {
              ???Bitmap?
              *pOrig?=?pb;???????????????//?remember?original?pb
              ???pb?=?new?Bitmap(*rhs.pb);??????//?make?pb?point?to?a?copy?of?*pb
              ???delete?pOrig;???????????????????????? //?delete?the?original?pb
              ???return?*this;
              }
              這樣的做法在解決以上兩個(gè)問(wèn)題的同時(shí)卻也降低了執(zhí)行的效率:不論什么情況,這個(gè)賦值函數(shù)都要?jiǎng)?chuàng)建一個(gè)新的Bitmap對(duì)象。
              當(dāng)然,Scott也辯證地道出了第一種方法的額外支出:判斷語(yǔ)句必然地引入了程序的分支(branch),于是指令的預(yù)取(prefetch)、緩沖(caching)、流水線處理(pipelining)的效率就會(huì)被降低。
            3. Copy And Swap。很深?yuàn)W的樣子。實(shí)際上就是改賦值為交換。例子在下面:

              Widget&
              Widget::operator=(Widget?rhs)????//?rhs?is?a?copy?of?the?object
              {?????????????????????????????????????//?passed?in?—?note?pass?by?val
              ???swap(rhs);???????????????????????????//?swap?*this's?data?with
              ????????????????????????????????????? ??????
              //?the?copy's
              ???return?*this;
              }


              利用參數(shù)傳值,隱性的構(gòu)造了一個(gè)Widget對(duì)象。然后將新對(duì)象和本對(duì)象中的數(shù)據(jù)成員交換,達(dá)到為本對(duì)象賦值的效果。新的臨時(shí)對(duì)象在跳出函數(shù)后自動(dòng)銷毀。剛才說(shuō)的兩個(gè)unsafe,都不會(huì)存在。
              不過(guò)又要回來(lái)說(shuō)效率,我總覺(jué)得這樣開銷還是大了,無(wú)論什么時(shí)候都要構(gòu)造新的對(duì)象。而且Scott本人也說(shuō)用swap來(lái)完成賦值的做法有點(diǎn)邏輯混淆。不過(guò)他老人家也說(shuō)了,這樣做很有可能讓編譯器生成更有效率的代碼(!!)沒(méi)有驗(yàn)證過(guò),暫且相信吧【等待論證的占位符】

            最后要炒的是第12項(xiàng),講的也還是拷貝運(yùn)算符:如何保證在賦值/拷貝的時(shí)候能夠?qū)⑺械某蓡T完整拷貝過(guò)去?對(duì)于簡(jiǎn)單的數(shù)據(jù)成員,編譯器自動(dòng)生成的拷貝函數(shù)可以保證一個(gè)不漏都幫你拷貝;如果是比較復(fù)雜的成員(比如說(shuō)指向一片內(nèi)存空間的指針),編譯器就沒(méi)有足夠的智商把這些成員拷貝到另外一個(gè)對(duì)象中去了。

            自己動(dòng)手豐衣足食,還是要自己寫。
            然而人寫的東西終究還是會(huì)有各種問(wèn)題,比如說(shuō):

            1. 在增加類成員以后有可能忘記更新拷貝函數(shù)(典型丟三落四……),顯然的結(jié)果就是新增加的數(shù)據(jù)成員沒(méi)有在拷貝函數(shù)中得到關(guān)照,拷貝不完全。
            2. 子類的拷貝函數(shù)把自己的成員都拷貝了,但是卻漏了把父類對(duì)象的成員拷貝到新的對(duì)象中。

            第一個(gè)問(wèn)題沒(méi)人能幫忙,只能靠自己小心。
            第二個(gè)問(wèn)題,方法比較直接了:在子類的拷貝函數(shù)中調(diào)用父類的拷貝函數(shù)(老爸,勞煩您也拷貝一下吧~~),代碼:

            Widget &
            Widget::
            operator ? = ?(Widget?src)??
            {
            ???swap(src);???????????????????????????????????
            // copy-and-swap
            ???WidgetParent:: operator ? = ?(src);?????? // invoking?the?parent's?copy?assignment?operator
            ??? return ? * this ;
            }


            最后的最后,通常來(lái)說(shuō)在拷貝函數(shù)和拷貝構(gòu)造函數(shù)中的實(shí)現(xiàn)大多相同,大師就很貼心的提醒:不要在拷貝函數(shù)中調(diào)用拷貝構(gòu)造函數(shù)或者反之。如果真的需要避免代碼的重復(fù),大可定義一個(gè)私有的函數(shù)來(lái)負(fù)責(zé)前面兩者相同的部分。

            posted on 2009-12-18 22:18 Justin.H 閱讀(1191) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Effective C++ 炒冷飯
            伊人久久精品线影院| 无码8090精品久久一区| 久久天天躁狠狠躁夜夜躁2O2O| 久久精品无码一区二区无码| 久久久久亚洲AV无码专区体验| 久久综合九色综合精品| 亚洲精品高清一二区久久| 久久久久亚洲av综合波多野结衣| 国产精品一区二区久久国产| 人妻少妇精品久久| 久久成人国产精品二三区| 青青热久久国产久精品| 精品无码久久久久久尤物| 欧美久久久久久| 97精品国产97久久久久久免费| 久久综合久久美利坚合众国| AA级片免费看视频久久| 一本色道久久HEZYO无码| 久久久精品日本一区二区三区| 国内精品久久人妻互换| 国产aⅴ激情无码久久| 久久天天日天天操综合伊人av| 久久精品国产亚洲欧美| 亚洲国产精品久久久天堂| 色婷婷狠狠久久综合五月| 国产精品青草久久久久福利99| 无码精品久久久久久人妻中字| 久久精品视频一| 少妇熟女久久综合网色欲| 亚洲国产成人乱码精品女人久久久不卡| 国产精品久久网| 久久国产精品-国产精品| 韩国免费A级毛片久久| 久久久久久久久久久久中文字幕| 亚洲欧美成人综合久久久| 一本一本久久aa综合精品| 国产偷久久久精品专区| 久久久老熟女一区二区三区| 久久国产精品成人片免费| 丰满少妇高潮惨叫久久久| 免费精品99久久国产综合精品|