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

            • 隨筆 - 50
            • 文章 - 42
            • 評論 - 147
            • 引用 - 0

            留言簿(6)

            隨筆分類

            文章分類

            Link

            搜索

            •  

            積分與排名

            • 積分 - 164634
            • 排名 - 159

            最新評論

            閱讀排行榜

            評論排行榜

            MSVC++ 對象內(nèi)存模型深入解析與具體應(yīng)用 (二)

            MSVC++ 對象內(nèi)存模型深入解析與具體應(yīng)用

            前言:本文之所以強調(diào)MSVC, 旨在提醒讀者在不同平臺和解釋器下內(nèi)存布局和實現(xiàn)上存在差異,但編程思想通用,文中內(nèi)容大多來自筆者實際工作經(jīng)驗和網(wǎng)上搜集,力求正確,但水平有限,如有不當之處,敬請指出

            面向?qū)ο螅罕疚拿嫦蛴幸欢?/span>C/C++基礎(chǔ),并且可以讀懂部分匯編的讀者

            版權(quán):歡迎轉(zhuǎn)載,但請注明出處http://www.shnenglu.com/dawnbreak/ 保留對本文的一切權(quán)力

            目錄
            1. C++基本類型與結(jié)構(gòu)體內(nèi)存布局
                            Key words: class,  struct, memory alignment

            2.虛表, 多態(tài)與動態(tài)綁定

                            Key words: Virtual Table, polymiorphism

            3.對象池

                            Key words: object pool , reload, new ,delete

            4.內(nèi)存泄漏檢測

                            Key words: memory leak detect

            5.智能指針

                            Key words: smart pointer

            6.   編譯期類型約束
               
                            Key words: compile-time ,type-constraint


             Appendix 1: C++堆棧祥解



            第二章  虛表, 多態(tài)與動態(tài)綁定

            Key words: Virtual Table, polymiorphism

            1.虛表-Virtual Table 多態(tài)-polymiorphism

                   虛函數(shù)表由虛函數(shù)的地址組成,表中函數(shù)地址的順序和它們第一次出現(xiàn)的順序(即在類定義的順序)一致。若有重載的函數(shù),則替換掉基類函數(shù)的地址,事實上你可以簡單的將虛表定義理解如下:

                    Int* virtualTable[size]//普通的指針數(shù)組而已

                    
            多數(shù)情形下,MSVC的類按如下格局分布:

            ?           指向虛函數(shù)表的指針(_vtable__vftable_),不過它只在類包括虛函數(shù),以及不能從基類復(fù)用合適的函數(shù)表時才會被添加。

            ?           基類。

            ?             函數(shù)成員。

            請看如下例子:


            #include "stdafx.h"
            #include 
            "assert.h"
            #include 
            "iostream"
            using namespace std;
            class A
            {
            public:
              
            int b1;
              
            static int b3;
              
            int b2;
            public:

              
            virtual void A_virt1()
              
            {
                  std::cout
            <<"  call of first A's vf"<<std::endl;
              }


              
            virtual void A_virt2()
              
            {
                  std::cout
            <<"  call of second A's vf"<<std::endl;
              }


            }
            ;
            int A::b3=100;
            //#pragma pack(1)
            class B:public A
            {
                
            int a1;
                
            char b1;
                
            float c1;
              
            virtual void A_virt2()
              
            {
                  std::cout
            <<"  call of second B's vf"<<std::endl;
              }
                
              
            virtual void B_virt1()
              
            {
                    std::cout
            <<"  call of second B's vf1"<<std::endl;
              }

                
            virtual void B_virt2()
              
            {
                    std::cout
            <<"  call of second B's vf2"<<std::endl;
              }

                
            void getsome();
            }
            ;
            void B::getsome()
            {
                
            int a=1;
            }


            class D:public A
            {
            }
            ;

            class C:public B,public D
            {
              
            virtual void B_virt1()
              
            {
                    std::cout
            <<"  call of first C's vf"<<std::endl;
              }

            }
            ;
            int _tmain(int argc, _TCHAR* argv[])
            {
                typedef 
            void(*pfunc)();
                cout
            <<"test the class memory layout-virtual table"<<endl;
                C cc;
                (pfunc(((
            int**)(&cc))[0][0]))();
                (pfunc(((
            int**)(&cc))[0][1]))();
                (pfunc(((
            int**)(&cc))[0][2]))();
                (pfunc(((
            int**)(&cc))[0][3]))();

                system(
            "pause");
                
            return 0;
            }

            程序輸出結(jié)果:


            以下是各個類在內(nèi)存中的布局圖

            class A size(12):
             
            +---
             
            0 | {vfptr}
             
            4 | b1
             
            8 | b2
             
            +---
            A::$vftable@:
             
            | &A_meta
             
            |  0
             
            0 | &A::A_virt1
             
            1 | &A::A_virt2
            A::A_virt1 
            this adjustor: 0
            A::A_virt2 
            this adjustor: 0
            class B size(24):
             
            +---
             
            | +--- (base class A)
             
            0 | | {vfptr}
             
            4 | | b1
             
            8 | | b2
             
            | +---
            12 | a1
            16 | b1
               
            | <alignment member> (size=3)
            20 | c1
             
            +---
            B::$vftable@:
             
            | &B_meta
             
            |  0
             
            0 | &A::A_virt1
             
            1 | &B::A_virt2
             
            2 | &B::B_virt1
             
            3 | &B::B_virt2
            B::A_virt2 
            this adjustor: 0
            B::B_virt1 
            this adjustor: 0
            B::B_virt2 
            this adjustor: 0
            class D size(12):
             
            +---
             
            | +--- (base class A)
             
            0 | | {vfptr}
             
            4 | | b1
             
            8 | | b2
             
            | +---
             
            +---
            D::$vftable@:
             
            | &D_meta
             
            |  0
             
            0 | &A::A_virt1
             
            1 | &A::A_virt2
            class C size(36):
             
            +---
             
            | +--- (base class B)
             
            | | +--- (base class A)
             
            0 | | | {vfptr}
             
            4 | | | b1
             
            8 | | | b2
             
            | | +---
            12 | | a1
            16 | | b1
               
            | | <alignment member> (size=3)
            20 | | c1
             
            | +---
             
            | +--- (base class D)
             
            | | +--- (base class A)
            24 | | | {vfptr}
            28 | | | b1
            32 | | | b2
             
            | | +---
             
            | +---
             
            +---
            C::$vftable@B@:
             
            | &C_meta
             
            |  0
             
            0 | &A::A_virt1
             
            1 | &B::A_virt2
             
            2 | &C::B_virt1
             
            3 | &B::B_virt2
            C::$vftable@D@:
             
            | -24
             
            0 | &A::A_virt1
             
            1 | &A::A_virt2
            C::B_virt1 
            this adjustor: 0

            為了調(diào)用虛函數(shù),編譯器首先需要從_vftable_取得函數(shù)地址,然后就像調(diào)用簡單方法一樣(例如,傳入_this_指針作為隱含參數(shù))。例如:

                      cc.A_virt2()

                      ;esi = ptr [cc]

                      mov eax, [esi]  ;fetch virtual table pointer

                      mov ecx, esi

                      call [eax+4]  ;call second virtual method

                      ;cc->B_virt1()

                      ;edi = pC

                      lea edi, [esi+8] ;adjust this pointer

                      mov eax, [edi]   ;fetch virtual table pointer

                      mov ecx, edi

            call [eax]       ;call first virtual method


            注意到上面class A的內(nèi)存布局圖,首先是VT指針,然后是成員變量b1,b2, 而對于靜態(tài)成員b3并沒有體現(xiàn),事實上b是存儲在程序的全局靜態(tài)數(shù)據(jù)區(qū),供該類的所有實例共享,這里請注意在classA中虛表中虛函數(shù)出現(xiàn)的順序和位置,這一點很重要,接著再看classB中虛函數(shù)出現(xiàn)的順序和位置,注意到A_virt1,A_virt2在classA和classB中出現(xiàn)的順序和位置一致,而所不同的是在classB的虛表中A_virt2已經(jīng)被替換,這就是多態(tài)的關(guān)鍵所在,每一個虛函數(shù)本身其實不過是一個固定的偏移量,而真正實現(xiàn)多態(tài)的其實是在編譯器的虛函數(shù)表的替換動作.

            而對于多繼承情況要復(fù)雜一些,例如在ClassC中每一個繼承路徑中都存在一個虛表,如果在沒函數(shù)里再加入如下調(diào)用:
             (pfunc(((int**)(&cc))[6][0]))();
             (pfunc(((int**)(&cc))[6][1]))();
            會輸出:
            call of first A's vf
            call of second A' vf
            這樣一個類中同時存在兩個一抹一樣的函數(shù),那么當你用
            C cc;
            cc.A_virt2()時會怎么樣呢?
            你會得到以下錯誤:
            error C2385: ambiguous access of 'A_virt2'

            解決辦法有兩種:
            1. 調(diào)用時加入域操作符,例如:
            cc.A::A_virt2();
            cc.B::A_virt2( );
            這種辦法最穩(wěn)妥也最清晰
            2. 使用虛基類
            代碼改動如下:

            。。。。。。。
            class B:virtual public A
            。。。。。。。
            class D:virtual public A
            。。。。。。。
            int _tmain(int argc, _TCHAR* argv[])
            {
            。。。。。。。
             (pfunc(((int**)(&cc))[0][0]))();
             (pfunc(((int**)(&cc))[0][1]))();
             //(pfunc(((int**)(&cc))[0][2]))();
             //(pfunc(((int**)(&cc))[0][3]))();
             //(pfunc(((int**)(&cc))[6][0]))();
             //(pfunc(((int**)(&cc))[6][1]))();
             cc.A::A_virt2();
             cc.A_virt2();
            。。。。。。。。
            }

            內(nèi)存布局變?yōu)椋?br>

            class C size(36):
             
            +---
             
            | +--- (base class B)
             
            0 | | {vfptr}
             
            4 | | {vbptr}
             
            8 | | a1
            12 | | b1
               
            | | <alignment member> (size=3)
            16 | | c1
             
            | +---
             
            | +--- (base class D)
            20 | | {vbptr}
             
            | +---
             
            +---
             
            +--- (virtual base A)
            24 | {vfptr}
            28 | b1
            32 | b2
             
            +---
            C::$vftable@B@:
             
            | &C_meta
             
            |  0
             
            0 | &C::B_virt1
             
            1 | &B::B_virt2
            C::$vbtable@B@:
             
            0 | -4
             
            1 | 20 (Cd(B+4)A)
            C::$vbtable@D@:
             
            0 | 0
             
            1 | 4 (Cd(D+0)A)
            C::$vftable@A@:
             
            | -24
             
            0 | &A::A_virt1
             
            1 | &thunk: this-=4goto B::A_virt2

             

            多了一個vbtable存儲偏移量,第一個元素存儲vbtable與該類的偏移量,第二個元素存儲vbtable與公共基類的偏移量,而且注意到,vftable@A 的第二個虛函數(shù)被定向到B:A_virt2
            這樣問題解決了,但是你會得到一個警告:
            Warning 1 warning C4250: 'C' : inherits 'B::B::A_virt2' via dominance
            顯示繼承了 'B::B::A_virt2‘ ,也就是說你在調(diào)用
            cc.A_virt2時,默認直接去調(diào)用B::A_virt2,這可能并不是你所期望的,所以使用時需要慎重


            2 . 動態(tài)邦定與靜態(tài)邦定
            邦定是指一個計算機程序自身彼此關(guān)聯(lián)的過程。按照邦定所進行的階段不同,可分為兩種不同的邦定方法:靜態(tài)邦定和動態(tài)邦定。
            靜態(tài)邦定
            靜態(tài)邦定是指邦定工作出現(xiàn)在編譯連接階段,這種邦定又稱早期邦定,因為這種邦定過程是在程序開始運行之前完成的。
            在編譯時所進行的這種邦定又稱靜態(tài)束定。在編譯時就解決了程序中的操作調(diào)用與執(zhí)行該操作代碼間的關(guān)系,確定這種關(guān)系又稱為束定,在編譯時束定又稱靜態(tài)束定。
             1class AA
             2{
             3public:
             4   void test()
             5   {
             6      cout<<"I am class AA!"<<endl;
             7   }

             8}
            ;
             9class BB
            10{
            11public:
            12   void test()
            13   {
            14      cout<<"I am class BB!"<<endl;
            15   }

            16}
            ;
            17int _tmain(int argc, _TCHAR* argv[])
            18{
            19    AA *A=(AA *)(new BB);
            20    A->test();
            21}

            讀者可以想一下以上例子的結(jié)果,如果說是I am class BB!

            C++沒有你想得那么職能,C++調(diào)用函數(shù)不過是指針偏移,而一般成員函數(shù)代碼是在數(shù)據(jù)存儲區(qū)的共享代碼段,聲明了AA類的指針 A 就已經(jīng)指定了偏移的起點是類型AA的代碼段起點,這一步就是所謂的動態(tài)邦定,而調(diào)用->test();只能得到I am class AA!

            也許你要說我并沒有實例化AA怎么會有那一段代碼呢,請注意代碼生成和實例化是完全不同的兩個階段,編譯在編譯時發(fā)現(xiàn)你調(diào)用了AA::test(); 那么就會載入相應(yīng)的symbol,程序啟動時就會載入相應(yīng)代碼段。

            也許你還要說沒有用繼承的關(guān)系,那么你可以自己試驗一下使BB繼承自AA 結(jié)果還是一樣的

            想要實現(xiàn)想要的結(jié)果唯一的方法就是使用虛函數(shù)來實現(xiàn)動態(tài)邦定;

             

            posted on 2009-03-11 14:25 pear_li 閱讀(2051) 評論(4)  編輯 收藏 引用 所屬分類: C++

            評論

            # re: MSVC++ 對象內(nèi)存模型深入解析與具體應(yīng)用 (二) 2009-03-11 15:07 電腦學(xué)習(xí)步步高

            剛發(fā)現(xiàn)的好玩的網(wǎng)站想玩來http://my.diannaobbg.cn/invite.php?u=1&c=be7fce657cf06905
            http://www.diannaobbg.cn
              回復(fù)  更多評論    

            # re: MSVC++ 對象內(nèi)存模型深入解析與具體應(yīng)用 (二) 2009-03-12 12:49 夢在天涯

            你可以研究下對象與對象的類型信息怎么聯(lián)系起來的,就是當調(diào)用dynamic_cast的時候為什么能夠正確的識別對象的類型!

              回復(fù)  更多評論    

            # re: MSVC++ 對象內(nèi)存模型深入解析與具體應(yīng)用 (二) 2009-03-12 12:53 夢在天涯

            加油!
              回復(fù)  更多評論    

            # re: MSVC++ 對象內(nèi)存模型深入解析與具體應(yīng)用 (二) 2012-09-07 11:02 劉偉

            如果把內(nèi)存布局畫成圖就更好了,像《Inside the C++ Object Model》那樣。感謝樓主的文章。學(xué)習(xí)了
              回復(fù)  更多評論    
            久久青青草原亚洲av无码app| 国产亚州精品女人久久久久久 | 久久精品国产99久久久香蕉 | 69久久精品无码一区二区| 久久久噜噜噜久久中文字幕色伊伊| 国产亚洲欧美精品久久久| 久久久久久国产a免费观看黄色大片| 亚洲午夜久久影院| av无码久久久久不卡免费网站| 91精品免费久久久久久久久| 精品久久久久成人码免费动漫| 久久综合色之久久综合| 五月丁香综合激情六月久久 | 91精品国产综合久久精品| 久久精品国产亚洲7777| 99久久无码一区人妻a黑| 亚洲欧美一级久久精品| 日产久久强奸免费的看| 久久久久无码精品国产app| 国产产无码乱码精品久久鸭 | 99久久精品费精品国产一区二区| 久久综合亚洲色HEZYO国产| 国产精品久久久久天天影视| 久久人妻少妇嫩草AV蜜桃| 久久精品国产乱子伦| 久久91精品综合国产首页| 国产精品久久久久9999高清| 伊人久久综合无码成人网| 77777亚洲午夜久久多喷| 国产成人久久精品一区二区三区 | 欧美久久天天综合香蕉伊| 色综合久久久久| 国产—久久香蕉国产线看观看 | 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 成人妇女免费播放久久久| 无码精品久久久久久人妻中字| 久久久黄色大片| 久久人做人爽一区二区三区| 伊人久久一区二区三区无码| 久久精品国产欧美日韩99热| 亚洲精品高清一二区久久|