C++對象內存分布詳解(包括字節對齊和虛函數表)


1、C++對象的內存分布和虛函數表:

C++對象的內存分布和虛函數表注意,對象中保存的是虛函數表指針,而不是虛函數表,虛函數表在編譯階段就已經生成,同類的不同對象中的虛函數指針指向同一個虛函數表,不同類對象的虛函數指針指向不同虛函數表。

2、何時進行動態綁定:

(1)每個類對象在被構造時不用去關心是否有其他類從自己派生,也不需要關心自己是否從其他類派生,只要按照一個統一的流程:在自身的構造函數執行之前把自己所屬類(即當前構造函數所屬的類)的虛函數表的地址綁定到當前對象上(一般是保存在對象內存空間中的前4個字節)。因為對象的構造是從最基類部分(比如A<-B<-C,A是最基類,C是最派生類)開始構造,一層一層往外構造中間類(B),最后構造的是最派生類(C),所以最終對象上綁定的就自然而然就是最派生類的虛函數表。

(2)析構函數的調用跟構造函數的調用順序是相反的,它從最派生類的析構函數開始的。也就是說當基類的析構函數執行時,派生類的析構函數已經執行過,派生類中的成員數據被認為已經無效(包括派生類對象中的虛表指針)。假設基類中虛函數調用能調用得到派生類的虛函數,那么派生類的虛函數將訪問一些已經“無效”的數據,所帶來的問題和訪問一些未初始化的數據一樣。而同樣,我們可以認為在析構的過程中,虛函數表也是在不斷變化的,不斷解綁定。

因此,在基類構造函數或者析構函數中調用虛函數,並不會綁定到派生類的實現上,因為在這兩個函數執行時虛函數表指針指向的是基類的虛函數表。

3、C++中類的大小:

由 1 可知,C++對象中只保存非靜態數據成員,成員函數和靜態數據成員是存儲在靜態數據區的。

字節對齊(默認):

1、VC規定各成員變量存放的起始地址相對於結構的起始地址的偏移量必須為該變量的類型所占用的字節數的倍數。

2、VC為了確保結構的大小為結構的字節邊界數(即該結構中占用最大空間的類型所占用的字節數)的倍數,所以在為最后一個成員變量申請空間后,還會根據需要自動填充空缺的字節。

3、如果對齊字節數(#pragma pack(n)),那么

(1)各成員變量存放的起始地址相對於結構的起始地址的偏移量必須為該變量的類型所占用的字節數和n的較小值的倍數。

(2)結構的大小為結構中占用最大空間的類型所占用的字節數和n的較小值的倍數。

class A { 
 double d;
 static int i;
 void f() { std::cout << "A::f" << std::endl; }
}; // 8 byte,只有double數據成員占8字節,成員函數和靜態數據成員不在對象中,而是在靜態數據區


class B { 
 int i; //4
 double j;//8
 char k; //
}; // 24 byte,考慮字節對齊, 4 + 4 + 8 + 1 + 7, 藍色的4是為了滿足條件1,黑色的7是為了滿足條件2。如果指定4字節對齊,4 + 8 + 1 + 3


class C { 
 virtual void f() { std::cout << "C::f" << std::endl; }
}; // 4 byte,虛函數表指針占4個字節


class D { 
};// 1 byte,沒有成員變量的結構或類的大小為1,因為必須保證結構或類的每一 個實例在內存中都有唯一的地址

注:

1、如果有成員對象,直接把成員對象展開到外部對象中,然后按照字節對齊的規律求大小。

2、虛繼承的內存分布為:虛類指針-》派生類成員數據-》基類成員數據。其對齊方案是:首先把派生類所有成員當成一個嵌套結構體形式,位於最下面的基類的數據成員要保證自己對齊(首地址整除自己的字節數),但是不用在最下面添加字節保證整體是邊界長度的整數倍(因為基類成員共享,不能把派生類當成一個整體)。

3、如果對象中有數組,可以把數組展開到對象中,然后按照字節對齊的規律求大小。

4、為什么要進行字節對齊

計算機組成原理教導我們這樣有助於加快計算機的取數速度,否則就得多花指令周期了。為此,編譯器默認會對結構體進行處理(實際上其它地方的數據變量也是如此),讓寬度為2的基本數據類型(short等)都位於能被2整除的地址上,讓寬度為4的基本數據類型(int等)都位於能被4整除的地址上,以此類推。比如有些平台每次讀都是從偶地址開始,如果一個int型(假設為32位系統)如果存放在偶地址開始的地方,那么一個讀周期就可以讀出這32bit,而如果存放在奇地址開始的地方,就需要2個讀周期,並對兩次讀出的結果的高低字節進行拼湊才能得到該32bit數據。

備注:visual studio 2010是按照默認方式進行字節對齊的 32位gcc按照4字節最齊


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM