什麼是ebc和ebo
ebc英文全稱為「empty base class」,中文全稱「空基類」。那什麼是空基類呢?簡單的
說就是沒有任何資料成員的類就稱之為空基類。也就是ebc的類定義中不包含任何資料成員,
那麼這樣一來可能大家會認為乙個ebc的尺寸(sizeof)因該是0,確實按照定義而言因該是
這樣的,但是我們知道即使是乙個ebc也可以定義乙個物件,而物件是乙個執行時的記憶體實
體,也就是說物件是必須要能夠通過記憶體位址進行區分的,那麼即使是乙個ebc類的物件也
必須占有記憶體空間,這樣一來一般情況下編譯器會將ebc的尺寸看作1位元組,也就是讓其物件
占用乙個位元組的空間,這樣一來既可以達到物件的位址鑑別,同時也是乙個比較節約記憶體的
分配策略。例如:
#include
struct cemptyclass {};
int main( int argc, char *argv )
通過上面的討論已經知道什麼是空基類了,那麼下面這些的類屬於空基類麼?
struct cemptyclass1 ; ~cemptyclass1() {} };
struct cemptyclass2 };
struct cemptyclass3 };
struct cemptyclass4 : public cemptyclass1 {};
struct cemptyclass5 : public cemptyclass3 {};
struct cemptyclass6 ;
struct cemptyclass7 : public cemptyclass6 {};
struct cemptyclass10 : virtual public cemptyclass1 {};
struct cemptyclass11 : virtual public cemptyclass1 {};
struct cemptyclass12 : public cemptyclass10, public cemptyclass11 {};
根據上面的定義「沒有任何資料成員」,這裡的資料成員不僅僅包括類的成員變數,同
時還包括編譯器為了某種目的引入的資料成員,比如:為了支援多型而引入的虛指標vptr、
為了支援虛繼承而引入的必要的虛基類指標等,而且還包括從基類繼承直接或間接繼承而
來的上述的資料成員。那麼這樣一來,上面的問題就很清楚了,cemptyclass3、
cemptyclass5、cemptyclass6、cemptyclass7、cemptyclass10、cemptyclass11、
cemptyclass12就不是ebc了,而cemptyclass1、cemptyclass2、cemptyclass4仍然是ebc。
那麼可能有些人會看出來如果這樣的乙個類,他的尺寸是多少呢?
struct cemptyclass20 : public cemptyclass1, public cemptyclass2 {};
struct cemptyclass21 : public cemptyclass1 ;
struct cemptyclass22 : public cemptyclass1, public cemptyclass2 ;
struct cemptyclass23 : public cemptyclass1, public cemptyclass6 {};
在vc++8和g++3.4.x(g++4以上版本編譯上述**出現編譯錯誤)版本時所出現的結果
會比較出人意料:
sizeof( cemptyclass20 ) == 1
sizeof( cemptyclass21 ) == 4
sizeof( cemptyclass22 ) == 8
sizeof( cemptyclass23 ) == 4
為什麼會出現上述的結果呢?這個主要是因為編譯器實施ebo所致的。那什麼是ebo呢?
ebo英文全稱「empty base class optimize」,中文全稱「空基類優化」。其實就是在ebc類被
繼承的是時候由於空基類沒有任何資料成員所以可以讓其在子類的物件布局中優化掉ebc所
占用的那乙個位元組,用子類物件的首位址作為ebc的子物件的首位址(也就是this指標)。
需要注意的是並不是每一次ebo優化都回被成功的實施,有時候由於繼承關係和物件布局
問題會導致無法實施ebo優化,從而導致ebc的子物件必然會在子類的物件中占用一定的空
間(一般會大於1個位元組,主要是因為記憶體對齊的需要)。
我們來分析上面的的4個繼承類的尺寸現象問題:
1. sizeof( cemptyclass20 ) == 1;cemptyclass20類繼承於兩個ebc類,同時自己也
是乙個ebc類,所以編譯器會自動地優化掉兩個基類的子物件的記憶體空間,所以尺寸
仍然是1位元組;
2. sizeof( cemptyclass21 ) == 4;cemptyclass21類繼承於乙個ebc類,同時自己也
包含乙個4位元組的成員變數,此時可以成功的實施ebo優化將ebc的記憶體空間優化掉;
3. sizeof( cemptyclass22 ) == 8;cemptyclass22類繼承於兩個ebc類,同時自己也
包含乙個4位元組的成員變數,按一般常理而言此時編譯器應該可以優化掉兩個ebc所
需要的記憶體空間,從而使得其尺寸僅僅只有4個位元組,可是為什麼會有8個位元組呢?
也就是說此時編譯器並沒有實施ebo優化,使得每乙個ebc子物件都回占用1個位元組的
記憶體,從而占用2位元組記憶體,再加上32位系統下的對齊需要填充2個位元組已形成4位元組
對齊,所以會導致其成為8個位元組;
4. sizeof( cemptyclass23 ) == 4;cemptyclass23類繼承於乙個ebc類和乙個非ebc類,
而cemptyclass6因為含有乙個vptr所以具有4位元組尺寸,而cemtpyclass23內本身不
包含任何資料成員,通過ebo優化掉第乙個ebc的記憶體,所以其尺寸就是4位元組。
通過上面的分析可以看出來,一般情況下如果子類的基類列表中只有乙個ebc時時一定
可以成功實施ebo優化的,而如果出現多繼承於多個ebc時會根據子類是否包含資料成員而
確定能夠實施ebo優化,同時會和編譯器的優化策略具有較大的關係。
在boost庫中有非常多的機制依賴於ebo優化,比如:nocopyable等,充分的理解ebc/ebo
並利用其所具有的記憶體優化特徵,會在類繼承體系中引入行為/策略的同時不導致物件的膨脹。
什麼是 PM,什麼是 SCM,和 NVM 什麼關係
自 近幾年,不論在學術界還是工業界,nvm 都是比較前沿的技術。其實 nvm 一詞並不新,是因為 pm 或稱 scm 這個與 nvm 有關的概念的出現,使得 nvm 這詞又 火 了一把。在近年的相關文獻中,nvm 也經常被和 pm scm 混用,讓人搞不清。本文捋一捋它們之間的關係。準確來說,nvm...
什麼是IoC和DI?什麼是依賴注入和控制反轉?
這東西,簡單一點說得清楚就對了。di dependency injection,依賴注入 依賴注入的概念就是將物件交給spring容器託管,要用的時候由spring容器注入到類中去用,spring是容器通過xml來宣告物件,另外,spring中的dao 資料訪問物件 介面 和dao.impl imp...
iptables之二 什麼是」表「和什麼是」鏈「
前一篇文章,介紹了iptables的基本資訊和資料報過濾原理。雖然已經比較簡單了,但還是有點雲裡霧裡的。那麼這次就從另乙個角度再說一下。先簡單回顧一下,iptalbes主要由 三表五鏈 組成,分別為 表 filter表,nat表,mangle表 鏈 prerouting,input,output,f...