眾所周知C++在底層背著程序員做了很多不為人知的隱秘工作,如果我們不了解其中的一些替換,則很可能出現(xiàn)結(jié)果跟我們料想的結(jié)果很不一致的情況。
下面我們就討論一下我們親手所構(gòu)造出的對(duì)象的大小可能出乎你意料的情況:
說明: 編譯器:gcc version 4.8.1 系統(tǒng)環(huán)境:64位opensuse 13.1
情況1: 空對(duì)象大小
我們用以下代碼:
#include <iostream>using namespace std ;class A{};int main(){ A a ; cout << "sizeof a is : " << sizeof(a) << endl ; return 0 ;} |
構(gòu)造一個(gè)空類A并實(shí)例化一個(gè)a對(duì)象,求出其大小:
大小為1個(gè)字節(jié),那這一個(gè)字節(jié)怎么來的呢?
原因:編譯器會(huì)在空類中安插進(jìn)去一下char,目的是為了讓空類實(shí)例化出來的第一個(gè)對(duì)象在內(nèi)存中都有自己獨(dú)特的地址,比如下面的情況:
A a ; A b ; if(&a == &b) { cout << "addr of a equal to addr of b" << endl ; } |
a的地址和b的地址不相等并且相差一個(gè)字節(jié),正是編譯器安插進(jìn)來的1字節(jié)。
情況2:考慮Alignment時(shí)的對(duì)象大小
有兩個(gè)對(duì)象,留意它們內(nèi)部只是數(shù)據(jù)的聲明順序不一樣:
class A{ public: int int_1 ; short short_1 ; char char_1 ;};class B{ public: char char_1 ; int int_1 ; short short_1 ;}; |
然后我們看看它們的大?。?
cout << "sizeof int is : " << sizeof(int) << endl ; cout << "sizeof short is : " << sizeof(short) << endl ; cout << "sizeof char is : " << sizeof(char) << endl ; A a ; B b ; cout << "sizeof a is : " << sizeof(a) << endl ; cout << "sizeof b is : " << sizeof(b) << endl ; |
結(jié)果可能會(huì)讓你驚訝:
三個(gè)成員變量加起來理應(yīng)是7個(gè)字節(jié),但是a對(duì)象卻有8個(gè)字節(jié),b對(duì)象甚至達(dá)到12個(gè)字節(jié)。
這里就要考慮到 Data alignment(數(shù)據(jù)對(duì)齊)這個(gè)情況,wikipedia這樣解說這個(gè)術(shù)語(yǔ):
Data structure alignment is the way data is arranged and accessed in computer memory. It consists of two separate but related issues: data alignment and data structure padding. Data alignment means putting the data at a memory address equal to some multiple of the word size, which increases the system's performance due to the way the CPU handles memory. To align the data, it may be necessary to insert some meaningless bytes between the end of the last data structure and the start of the next, which is data structure padding.
https://en.m.wikipedia.org/wiki/Data_structure_alignment#
MSDN 寫道
Alignment is a property of a memory address, expressed as the
numeric address modulo a power of 2. For example, the address 0x0001103F
modulo 4 is 3; that address is said to be aligned to 4n+3, where 4
indicates the chosen power of 2. The alignment of an address depends on
the chosen power of two. The same address modulo 8 is 7.
An address is said to be aligned to X if its alignment is Xn+0.
CPUs execute instructions that operate on data stored in memory, and the data are identified by their addresses in memory.
-
Data alignment(數(shù)據(jù)對(duì)齊)
簡(jiǎn)單說就是為了CPU的讀取效率而把不同大小的數(shù)據(jù)安排在有規(guī)律的內(nèi)存地址上而定的一種屬性,比如我這里的 int 的alignment 為4,而short 的為2,char的為1。而這些變量所在的內(nèi)存起始地址要是它們的 alignment 的整數(shù)倍。
-
Data structure padding
在 class 的所有 member 的 alignment 中,找到 alignment 的最大值,在class的最后一個(gè)member填補(bǔ) padding bytes使整個(gè)class的size 為此aligment 的整數(shù)倍。
以上兩個(gè)概念詳細(xì)請(qǐng)參考:http://acoder.cc/Article/view/aid/424.html
有了以上兩個(gè)概念,我們就可以來討論對(duì)象a 和 b 的數(shù)據(jù)模型了:
對(duì)象a和b里最大的alignment為int的4個(gè)字節(jié),由于聲明順序不一樣,當(dāng)安排好了所有的數(shù)據(jù)后,a為了達(dá)到最大alignment的整數(shù)倍,要填充一個(gè)字節(jié)的padding(紅色字樣處),而b則需要填充兩個(gè)字節(jié)的padding(紅色字樣處)。
結(jié)果就出來了a是8個(gè)字節(jié)而b是12字節(jié)。
情況3:帶有虛函數(shù)的對(duì)象大小
看看這個(gè)例子:
class A{ public: A(){} virtual ~A(){} int int_1 ; short short_1 ; char char_1 ;}; |
我們順帶計(jì)算一下這個(gè)平臺(tái)環(huán)境下指針的大?。?
指針大小是8字節(jié),這個(gè)對(duì)象a與情況二的對(duì)象a只是多了一個(gè)虛析構(gòu)函數(shù)。但是其大小增加了8字節(jié)。
原 因:熟悉C++的都知道C++的多態(tài)實(shí)現(xiàn)是依靠虛函數(shù)及在運(yùn)行時(shí)使用pointer 或者 reference 來間接調(diào)用虛函數(shù),而C++會(huì)為每個(gè)帶有虛函數(shù)的類分配一個(gè)虛函數(shù)表,表中第一項(xiàng)記錄所有該類的每個(gè)虛函數(shù)的指針,這個(gè)表是這個(gè)類所有實(shí)例化的對(duì)象共享 的,這個(gè)類的所有對(duì)象上會(huì)被編譯器安插一個(gè)指針指向這個(gè)共享的虛函數(shù)表。(關(guān)于虛函數(shù)表詳細(xì)講解請(qǐng)看這里:http://acoder.cc/Article/view/aid/435.html)
就是說 a 對(duì)象的內(nèi)存開始位置會(huì)有一個(gè)被編譯器自動(dòng)安排插入的指針存在,而我們順帶求出的這個(gè)環(huán)境下指針是占用8?jìng)€(gè)字節(jié)的內(nèi)存的,而這個(gè)a對(duì)象在情況下求得8個(gè)字節(jié)大小加上編譯器自動(dòng)安插的指針,則剛好是16字節(jié)。
這是一個(gè)系列文章:第一篇請(qǐng)看這里: http://acoder.cc/Article/view/aid/280.html
歡迎關(guān)注ACoder技術(shù)社區(qū):http://acoder.cc
關(guān) 于這些C++的內(nèi)容為作者閱讀《嘗試探索C++對(duì)象模型》《C++ Primer》《Effective C++》理解所得,內(nèi)容如有不當(dāng)之處,請(qǐng)聯(lián)系w@programfish.com更正,轉(zhuǎn)載請(qǐng)注明來自“ACoder社區(qū)”及原文地 址:http://acoder.cc/Article/view/aid/436.html
學(xué)者網(wǎng)

評(píng)論 0