• <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++ 炒冷飯
            久久久久久免费一区二区三区| 大香网伊人久久综合网2020| 久久亚洲中文字幕精品一区| 2021国内久久精品| 久久精品国产亚洲av麻豆小说 | 久久99久久无码毛片一区二区| 国产亚州精品女人久久久久久 | 亚洲?V乱码久久精品蜜桃 | 久久AV高清无码| 青青国产成人久久91网| 2019久久久高清456| 国产福利电影一区二区三区,免费久久久久久久精 | 国产亚洲精久久久久久无码AV| 久久久久久午夜精品| 久久久久久a亚洲欧洲aⅴ | 一级做a爰片久久毛片毛片| 久久久国产乱子伦精品作者| 色99久久久久高潮综合影院 | 人妻无码精品久久亚瑟影视| 亚洲乱亚洲乱淫久久| 久久AV高清无码| 无码国内精品久久人妻| 伊人久久亚洲综合影院| 久久99精品国产99久久6| 久久66热人妻偷产精品9| 77777亚洲午夜久久多人| 亚洲国产精品成人AV无码久久综合影院| 狠狠88综合久久久久综合网| 性欧美大战久久久久久久久 | 久久精品九九亚洲精品| 久久99精品久久久大学生| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 亚洲AV日韩精品久久久久久| 国产欧美久久久精品影院| 久久亚洲av无码精品浪潮| 国产2021久久精品| 国产日韩久久久精品影院首页| 91麻豆精品国产91久久久久久| 99久久精品无码一区二区毛片| 7国产欧美日韩综合天堂中文久久久久 | 国内精品久久久久久久久电影网|