天天看點

C++中類的記憶體空間大小(sizeof)分析

    那麼在C++中的類的記憶體空間大小又有哪些特殊的問題呢?

    首先,我認為對齊肯定也是其中的問題之一,對齊主要是為了加快讀取的速度。

    關于對齊這個我認為基本上已經是作業系統内定好的,既然Linux與Windows存在差别,那麼在C++的類中,關于對齊肯定也會存在一定的差别。關于對齊我認為隻要記住平時使用的系統的對齊準則就可以了,即:在Windows中經常是以結構體重最大内置類型的存儲單元的位元組數作為對齊的基準,而在Linux中,所有的對齊都是以4個位元組對齊。

    其次,我認為就應該讨論在基類中哪些成員占有存儲空間,那些成員不占用記憶體空間?

    在C++中占存儲區間的主要是非static的資料對象,主要包括各種内置的資料類型,類對象等,類中的函數聲明以及函數定義都不算記憶體空間。但是需要注意所有的virtual函數(虛函數)共享一段記憶體區域,一般來說是4個位元組。為什麼隻是包含非static資料對象呢?因為static資料并不屬于類的任何一個對象,它是類的屬性,而不是具體某一個對象的屬性,在整個記憶體區域中隻有一個記憶體區域存儲對應的static資料,也就是所有的類對象共享這個資料,是以不能算做具體某一個對象或者類型的記憶體空間。

    是以可以認為基類對象的存儲空間大小為:

    非static資料成員的大小 + 4 個位元組(虛函數的存儲空間)

    當然這個大小不是所有資料成員大小的疊加,而是存在一個對齊問題,具體的應該參考相關的對齊文章。

    最後,我認為肯定要關心一下派生類的存儲空間了?

    在C++中,繼承類是一個比較有用的類,繼承使得各種類在基類的基礎上擴充,這時候派生類中包含了基類的資訊,一般而言,在基類中存在虛函數時,派生類中繼承了基類的虛函數,是以派生類中已經繼承了派生類的虛函數。是以繼承類中不能再添加虛函數的存儲空間(因為所有的虛函數共享一塊記憶體區域),而僅僅需要考慮派生類中心添加進來的非static資料成員的記憶體空間大小。

    是以可以認為派生類對象的存儲空間大小為:

    基類存儲空間 + 派生類特有的非static資料成員的存儲空間

   還有一類是比較特殊的情況,如果是虛繼承的情況下,這時的存儲空間大小就會發生變化。

    基類的存儲空間 + 派生類特有的非static資料成員的存儲空間 + 每一個類的虛函數存儲空間。

    下面我采用一些例子說明上面的問題:

    對齊的問題:

點選(此處)折疊或打開

class test

{

public:

        test();

private:

        int a;

        char c;

};

cout sizeof(test) endl;

  上面的代碼在linux以及windows下都會輸出8,而不是輸出5,這個是在C語言中已經讨論過的話題,但是說明對齊在C++中也是要考慮的。關于作業系統的差異在後面用一個統一的例子說明。

    虛函數問題

    為了讨論虛函數,我們在test類中添加一個虛析構函數,然後再測試結果。   

public:

        test();

        virtual ~test();

這段代碼與前面的代碼沒有什麼差別,隻是添加了一個虛函數,然後編譯調試,這時候輸出的結果12,也就是說增加了一個虛函數以後,類的資料成員增加了4個位元組,那麼是否是每一個虛函數都占有4個位元組呢?其實是不會的,在test中加入一個新的虛函數virtual void get_a_c(),這時在輸出的結果還是12,這說明所有的虛函數共享4個位元組。

    static資料

    我們知道static資料是非對象的屬性,而是類的屬性,他不能算是某一個對象或者類型的存儲空間,在類定義中隻能聲明,初始化隻能在類外執行,當然有例外的。這也不做分析了。具體參看後面的大例子。

    派生類的存儲空間

    派生類從基類中繼承了很多成員,自己也會增加很多的成員,由于虛函數也會被繼承下來,是以就是在派生類中不顯式定義虛函數,在派生類中也會存在從基類繼承下來的虛函數,是以虛函數不需要額外計算記憶體空間,而隻需要增加基類的非static成員資料大小。定義如下面所示,該函數會輸出20,剛好是添加的非static資料double d的存儲空間大小。證明了上面的分析。

        virtual void get_a_c();

class derived_test:public test

        virtual ~derived_test();

        double d ;

cout sizeof(derived_test) endl;

測試虛繼承的類的大小:

class A

        char i[3];

        virtual void a(){};

class B : public virtual A

        char j[3];

        virtual void b(){}

class C: public virtual B

        char k[3];

        virtual void c(){}

int main()

    cout "sizeof(A): " sizeof(A) endl;

    cout "sizeof(B): " sizeof(B) endl;

    cout "sizeof(C): " sizeof(C) endl;

    return 0;

}

下面采用一個比較綜合的例子說明一下作業系統以及各種綜合的影響分析。

#include iostream>

#include string>

#include vector>

    test();

    virtual ~test();

    virtual void get_a_c();

    int a;

    char c;

    virtual ~derived_test();

    double d ;

class base

    char a;

    static int refrence_count;

    std::string name;

    double price;

    std::vectordouble> dvec;

    base();

    virtual ~base();

    static int get_count();

int base::get_count()

    return refrence_count;

int base::refrence_count = 0;

class new_base

    new_base();

    virtual ~new_base();

int new_base::get_count()

int new_base::refrence_count = 0;

class derived: public base

    int min_qty;

    double discount;

    static int newp;

    derived();

    virtual ~derived(){};

class new_derived:public new_base

    int min_pty;

    new_derived();

    virtual ~new_derived(){}

    std::cout "The size of test is " sizeof(test) std::endl;

    std::cout "The size of derived_test is " sizeof(derived_test) std::endl;

    std::cout "The size of base is " sizeof(base) std::endl;

    std::cout "The size of new_base is " sizeof(new_base) std::endl;

    std::cout "The size of derived is " sizeof(derived) std::endl;

    std::cout "The size of new_derived is " sizeof(new_derived) std::endl;

上面在windows和linux的結果分别如下:

windows:

C++中類的記憶體空間大小(sizeof)分析

Linux:

C++中類的記憶體空間大小(sizeof)分析

從上面的結果可以之知道在兩個系統下,結果是不一樣的。說明作業系統也對類的存儲空間大小有較大的影響。