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

            大龍的博客

            常用鏈接

            統(tǒng)計(jì)

            最新評(píng)論

            關(guān)于NRV優(yōu)化

                在C++中,函數(shù)返回整數(shù)或指針是通過(guò)eax寄存器進(jìn)行傳遞的,理解起來(lái)比較簡(jiǎn)單。

                但是返回對(duì)象或結(jié)構(gòu)體一直是令人感到困惑的問(wèn)題。今天我整理了一下,將整個(gè)返回過(guò)程寫下來(lái),以作備用。

             

                還是先通過(guò)一個(gè)例子來(lái)理解這個(gè)問(wèn)題:

            首先,定義一個(gè)類Vector:

             

            class Vector
            {
            public:
                int x,y;
            };

             

            然后定義函數(shù)add()對(duì)Vector對(duì)象進(jìn)行操作:

            Vector add(Vector& a, Vector & b)
            {
                Vector v;
                v.x = a.x + b.x;
                v.y = a.y + b.y;
                return v;
            }

             

            現(xiàn)在的問(wèn)題是:

            如果調(diào)用如下語(yǔ)句:

            Vector a, b;
            Vector c = add(a, b);

            請(qǐng)問(wèn)從a, b傳入函數(shù)開始,一共創(chuàng)建了多少個(gè)對(duì)象?

             

            在通常情況下我們會(huì)做出如下分析:

            1. 在add()函數(shù)中創(chuàng)建對(duì)象v。

            2. 函數(shù)返回,創(chuàng)建一個(gè)臨時(shí)變量__temp0,并將v的值拷貝到__temp0中。

            3. 最后創(chuàng)建對(duì)象c,通過(guò)操作符=,將__temp0中的對(duì)象拷貝到c中。



             

            但其實(shí),我們會(huì)在后面看到,整個(gè)過(guò)程就只創(chuàng)建了1個(gè)對(duì)象:c。

             

            為了更清晰的分析整個(gè)調(diào)用過(guò)程,我們?yōu)閂ector加上默認(rèn)構(gòu)造函數(shù)和拷貝構(gòu)造函數(shù),并增加一個(gè)靜態(tài)變量count用于統(tǒng)計(jì)構(gòu)造函數(shù)調(diào)用次數(shù):

            class Vector
            {
            public:
                static int count;

                static void init()
                {
                    count = 0;
                }

                int x,y;

                Vector()
                {
                    x = 0;
                    y = 0;
                    
                    // For analysis.
                    count ++;
                    printf("Default Constructor was called.[0x%08x]\n", this);
                }

                Vector(const Vector & ref)
                {
                    x = ref.x;
                    y = ref.y;

                    // For analysis.
                    count ++;
                    printf("Copy Constructor was called.[copy from 0x%08x to 0x%08x].\n", &ref, this);
                }

            };

            int Vector::count = 0;

             

            然后在main()函數(shù)中寫上調(diào)用代碼:

                Vector a, b;
                Vector::init();
                printf("\n-- Test add() --\n");
                Vector c = add(a, b);
                printf("---- Constructors were called %d times. ----\n\n\n", Vector::count);

             

            使用cl編譯。

            (注:Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86, Microsoft (R) Incremental Linker Version 10.00.40219.01)

            完成后,運(yùn)行程序,得到如下結(jié)果:

            -- Test add() --
            Default Constructor was called.[0x0012fef8]
            Copy Constructor was called.[copy from 0x0012fef8 to 0x0012ff60].
            ---- Constructors were called 2 times. ----

             

            由此可知,在沒(méi)有優(yōu)化的情況下,整個(gè)調(diào)用過(guò)程共創(chuàng)建了兩個(gè)對(duì)象:

            即:c和__temp0.

             

            整個(gè)調(diào)用過(guò)程偽代碼如下:

            首先add()函數(shù)被編譯器看做:

            void add(Vector& __result, Vector& a, Vector & b)
            {
                __result.x = a.x + b.x;
                __result.y = a.y + b.y;
                return;
            }

            而調(diào)用代碼同時(shí)被修改為:

                Vector a, b;
                Vector::init();
                printf("\n-- Test add() --\n");
                Vector __temp0;        // 構(gòu)造函數(shù).
                add(__temp0, a, b);
                Vector c(__temp0);    // 拷貝構(gòu)造函數(shù).
                printf("---- Constructors were called %d times. ----\n\n\n", Vector::count);

             



             

            現(xiàn)在就可以理解輸出結(jié)果了吧。

            這里要強(qiáng)調(diào)一點(diǎn),看到”=”并不等于調(diào)用了Operator=()的代碼,以下三種情況其實(shí)是等效的,都只調(diào)用了拷貝構(gòu)造函數(shù):

            Vector b(a);
            Vector b = a;
            Vector b = Vector(a);

             

            最精彩的部分在于,如果你用

            cl /Ox

             

            編譯代碼,使優(yōu)化達(dá)到最大,再次運(yùn)行,得到如下結(jié)果:

            -- Test add() --
            Default Constructor was called.[0x0012ff74]
            ---- Constructors were called 1 times. ----

             

            這次,只調(diào)用了默認(rèn)構(gòu)造函數(shù)。這樣的修改被稱作Named Return Value(NRV) Optimization。

            什么是NRV優(yōu)化呢,顧名思義,就是保存返回值的變量不再使用沒(méi)名沒(méi)姓的__temp0這樣的東西了,而是直接把c作為返回變量,因此應(yīng)該將NRV翻譯為“有名字的返回變量”吧,侯捷翻譯的《深入探索C++對(duì)象模型》居然把它稱為“具名數(shù)值”,真是不知所云。

            言歸正傳,NVR優(yōu)化的偽代碼如下:

                Vector c;
                add(c, a, b);

            NVR優(yōu)化的最大好處就是不會(huì)再去調(diào)用那次多余拷貝構(gòu)造函數(shù)了(把__temp0拷貝到c),因此《深入探索C++對(duì)象模型》67頁(yè)最下面才會(huì)說(shuō)第一版沒(méi)有拷貝構(gòu)造函數(shù),所以不能進(jìn)行優(yōu)化。其實(shí)是指優(yōu)化的意義不大,或者說(shuō)沒(méi)有什么可優(yōu)化的。



            但是這樣帶來(lái)的壞處是,如果你在拷貝構(gòu)造函數(shù)里面放上與拷貝無(wú)關(guān)的代碼,比如我放入的printf和count++,那么這些東西就不會(huì)被調(diào)用了,產(chǎn)生優(yōu)化前后代碼不一致問(wèn)題。所以大家要在此注意一下。
            http://www.linuxso.com/linuxbiancheng/5726.html

            posted on 2012-03-28 17:30 大龍 閱讀(449) 評(píng)論(0)  編輯 收藏 引用


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


            久久无码人妻一区二区三区| 久久天天躁狠狠躁夜夜2020一| 伊人久久大香线蕉av不卡| 久久久久国产一级毛片高清板| 国产日产久久高清欧美一区| 久久久老熟女一区二区三区| 伊人久久大香线焦AV综合影院| 99久久这里只精品国产免费| 久久综合偷偷噜噜噜色| 漂亮人妻被中出中文字幕久久| 蜜桃麻豆www久久国产精品| 久久久精品人妻无码专区不卡 | 久久精品中文字幕一区| 94久久国产乱子伦精品免费| 久久久91精品国产一区二区三区| 国产99久久精品一区二区| 97热久久免费频精品99| 久久99久久99小草精品免视看| 久久久青草久久久青草| 久久久中文字幕日本| 久久久久久久91精品免费观看| 狠狠色噜噜色狠狠狠综合久久| 欧美一区二区三区久久综| 国产综合久久久久久鬼色| 久久国产精品一国产精品金尊| 国产一区二区精品久久| 久久99久久无码毛片一区二区| 色综合久久中文字幕综合网| 久久久久久国产精品美女| 久久精品人人做人人爽电影蜜月| 国产韩国精品一区二区三区久久| 久久亚洲国产欧洲精品一| 亚洲国产成人久久综合一区77| 精品久久久久久中文字幕大豆网| 99久久精品费精品国产一区二区 | 精品久久久久久国产牛牛app| 色偷偷88欧美精品久久久| 色欲久久久天天天综合网精品| 久久久久夜夜夜精品国产| 国产精品久久久久a影院| 久久se精品一区精品二区|