日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++类的内存布局

發布時間:2023/12/2 c/c++ 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++类的内存布局 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

by andydeng ? 2011 年 4 月 3 日 ? C++ ? 1 Comment

本文基本上是對于Stanley B.Lippman的Inside The C++ Object Model一書第一章第三章的概括,描述了c++類的內存布局情況.

c++的類的內存布局有如下規則:
1. Nonstatic data member 存放在Class Object中;
2. Static data member, static/nonstatic member function存放在class object之外.
3. 若類有virtural function, 則在class object 中增加virtual pointer(vptr)指向virtural function tabel(vtbl). vptr在類中的位置有兩種情況:1是在所有成員變量之后,這么做的好處是這個類能和c語言兼容.2是在最前面,這樣做的話,虛擬繼承等實現會方便一點,但是不能和c兼容.在前或后依賴編譯器實現.
4. nonstatic data member 若在同一個access section中, 則變量在內存中的順序保證和聲明中的順序一致(較晚出現的變量有較高的地址).而不同access section中的數據順序則沒有保證,依賴編譯器實現.
5. 內存對齊: 類的各個成員,第一個成員位于offset為0的位置,以后每個數據成員的偏移量必須是min(#pragma pack(), 這個數據成員自身的長度)的倍數
???????????? 數據成員自身對齊后, 類本身也要進行對齊, 對齊將按照min(#pragma pack(), 類中長度最大的成員)的倍數進行.
6. 如果類為空,編譯器會安插1byte的數據到類中,以確保類的每個實例都會有唯一的內存地址
7. 繼承后,子類的數據成員不會占用父類內存對齊用的空間. C++語言保證:"出現在derivd class 中的base class subobject有其完整的原樣性"
8. 如果類的繼承體系不是單一,而是多重繼承,但是不含虛擬繼承,那么有多少條繼承鏈,內存布局中就有多少個vptr.多個繼承鏈的位置,和繼承時的聲明順序一致.
9. 如果使用了虛擬繼承,則先將derived class的不變部分布局,然后再布局虛擬繼承的base class,而具體布局則有以下情況:
? 1. 使用Pointer Strategy, 每一個虛擬繼承的類,都有一個額外的指針指向base class
? 2. 使用Virtual table offset strategy, 不加入額外的指針指向base class,而是在vtbl的-1的offset內放置該類與虛擬繼承的基類之間的offset. 這樣的話運行時則可以通過derivedPointer + vptr[-1]得到.
? 3. 使用Virtual base class table. 這個是微軟的做法,不過書中并沒有具體描述怎么做,根據我的理解好像是在vtbl中加入一個指針指向base class.
如果采用2或3, 那么內存布局和8并不會有太大區別,就是virtual base class跑到最后面去了.
第9種情況異常復雜,建議看原書外加自己在多個編譯器上實踐實踐.

用實例來說說(32位機器)
規則1和2:
class A
{
public:
int a;
static char b;
void foo();
static void bar();
};
ASSERT(sizeof(A) == 4);
那么在每一個A對象內,只含有一個a,也就是,sizeof(A) == 4 .
而b,foo(),bar(),都不在class object之內,他們在內存中有唯一實體.

規則3
class B
{
public:
int a;
virtual void foo();
};
ASSERT(sizeof(B) == 8);
一個int和一個vptr,共8位

規則4,沒啥好說的,一般就算在不同的access section,都會按照一致的順序來聲明.但是要注意順序一致不代表連續.因為變量間可能會有一些bytes用于內存對齊.

規則5
class C
{
int a;
char b;
};
ASSERT(sizeof(C) == 8);
規則5有兩條子規則,第一條對這個例子沒用,經過第一條后C的大小還是5,可是第二條要求整個類要對齊,那么必須在char b后增加3bytes.
如果int和char的聲明順序反一下,那么為滿足第一條規則,類已經需要對齊成8了,已經是8那么第二條也滿足了.

規則6
class D
{};
ASSERT(sizeof(D) == 1);
這1byte是編譯器插進去的,如果不插的話,連續聲明D a,b;再取他們的地址,就會變成一樣的了.就無法分辨哪個變量是哪個了.
不過要注意的是,任何類繼承了D,只要里面有vptr或者任何一個變量,那么編譯器就不會在子類中加入這1 byte了.(這個是依賴于編譯器的,而不是標準規定.如果編譯器沒有去掉這1byte的話,那么就要內存對齊了.)

規則7
class E:public C
{
int c;
char d[2];
};
ASSERT(sizeof(E) == 16);
編譯器不會為了節省空間把E的成員插入到C為了內存對齊的而補出的空間中的.這道題我面試的時候被問過,我答16的時候面試官還認為錯了,太浪費空間了.但是這的確是唯一的正確解.

規則8
class F
{
int b;
virtual void bar();
};
class G:public B, public F
{
int c;
};
ASSERT(sizeof(G) == 20);
3個int,2個vptr,一共20

規則9
class H:virtual public B
{
int a;
};
class I:virtual public B
{
int b;
};
class J:public H, public I
{
int a;
};
ASSERT(sizeof(J) == 28);
4個int一共是16,BHI3個類都有各自的vptr,16+4*3==28.

這東西其實我一年半前就看書看到過,可惜實際編程中基本是用不到這種東西的,導致我忘了不少,面試的時候有幾個沒答出來,十分可惜,特意花一天時間重新啃了那書再總結總結加深記憶.另外真的要對自己說聲加油啊.

總結

以上是生活随笔為你收集整理的c++类的内存布局的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。