2014-09-02 122 views
2

這個問題的標題是相當複雜的,所以我會嘗試用一個例子對它進行框架。假設我有一個抽象基類,有許多繼承自它的類。在下面的例子中,我只展示了兩個繼承的類,但實際上可能會有更多。靜態分配繼承對象數組

class Base { 
public: 
    Base(); 
    virtual ~Base() = 0; 
/// Other methods/members 
}; 

class SmallChild: public Base { 
public: 
    SmallChild(); 
    ~SmallChild(); 
/// Other methods/members such that sizeof(SmallChild) < sizeof(LargeChild) 
}; 

class LargeChild : public Base { 
public: 
    LargeChild(); 
    ~LargeChild(); 
/// Other methods/members such that sizeof(LargeChild) > sizeof(SmallChild) 
}; 

我需要實現一個容器,它最多可以存儲N繼承的對象。這些對象需要在運行時創建/銷燬並放置在容器中,但由於項目中的約束(特別是在嵌入式硬件上),動態內存分配不是一種選擇。容器需要靜態分配所有空間。另外,編譯器不支持C++ 11。

只有一種方法可以實現。爲了引用N對象,我首先需要創建一個指向基類的指針數組,然後實際存儲對象,我需要創建一個足夠大的緩衝區來存儲最大繼承對象的副本,在這種情況下是LargeChild

Base * children[N]; 
uint8_t childBuffer[N * sizeof(LargeChild)]; 

我可以隨後在children分配指針橫跨childBuffer,每個都由sizeof(LargeChild)分離。由於需要創建對象,因此可以使用C++的「placement new」將它們放置在數組中的指定位置。我需要跟蹤childBuffer中每個對象的類型,以取消引用children中的指針,但這不應該太糟糕。

我有一個關於這個整個設置/執行幾個問題:

  1. 這是一個很好的方法爲我所描述它解決問題?我從來沒有像以前那樣執行過任何操作,所以我不知道我是否在這裏吃午飯,還有更簡單的方法來完成此任務。

  2. 這可以在編譯時完成多少?如果我有M類型的繼承類(SmallChild,LargeChild等)但我不知道知道它們的大小相互關係,我怎麼能確定大小childBuffer?這個大小取決於最大類的大小,但是有沒有辦法在編譯時確定這個大小?我可以想象一些預處理器宏遍歷類,評估sizeof並找到最大值,但是我對這個級別的預處理器工作很少有經驗,不知道這會是什麼樣子。我也可以想象使用模板可以做到這一點,但是我再也沒有關於編譯時模板魔法的經驗,所以我只是基於我的直覺。任何方向如何實施這將不勝感激。

+1

這有幫助嗎? http://stackoverflow.com/questions/354442/looking-for-c-stl-like-vector-class-but-using-stack-storage – PaulMcKenzie 2014-09-02 17:27:29

+0

如果你有一個派生類型的列表,那麼宏+預處理器可以工作與那個名單找到最大的類型。將所有派生類型的列表放在一個地方是否可行?另外,多大(約)是最大的? – 2014-09-02 17:43:05

+0

第一次擦除後是否會插入插入物,還是混在一起? – 2014-09-02 17:44:18

回答

3

您是否需要處理對象?否則,可能會更容易覆蓋operator new。我指的是:

void* operator new (std::size_t size) throw (std::bad_alloc); 

所有的覆蓋都會從一個大的緩衝區分配內存。 size參數表指定分配多少內存。

這樣,你應該能夠只是說

children[i] = new SmallChild(); 

編輯:如果你確實需要解除分配,則需要更復雜的數據結構。無論如何,您最終可能會重新實施堆。

+0

好吧,這比我想象的要容易得多。即使「重新實現堆」,如果他知道最大尺寸和最大計數,那麼「重新實現堆」可能相當麻煩。 – 2014-09-02 17:49:45

+0

對於「模擬堆」,可能每個類型都有一個緩衝區(一個char [...]類型的靜態變量,然後你得到一個分配的數字和單個鏈表的頭部空閒。分配的數量反映了bufer作爲塊數組的使用情況,一旦耗盡,我們使用爲我們創建的列表,因爲我們將其釋放。 – Arkadiy 2014-09-02 18:17:45

0

如果這組對象是完全靜態的(在構建時設置,並且在運行時不會改變),通常的做法是使用每個派生類的一組數組,並使用指針構建'global'數組到其他陣列:

static SmallChild small_children[] = { 
    { ...initializer for first small child... }, 
    { ...initializer for second small child... }, 
    ... 
}; 
static LargeChild large_children[] = { 
    { ...initializer for first large child... }, 
    ... 
}; 
Base *children[N] = { &small_children[0], &small_children[1], &large_children[0], .... 

如果有被添加的兒童這可以是棘手的,以保持/從構建除去頻繁,或者如果兒童數組中的順序是重要的。可能需要使用腳本或生成程序來生成上述源文件,該程序可以讀取所需孩子的描述。

0

考慮到您的限制(即不使用動態分配),您的方法很有趣。

事實上,你正在用自己的方式管理一組union anyChild { smallChild o1; largeChild o2; ... };sizeof(anyChild)會給你最大的塊大小,你正在尋找。

順便說一句,只要所有對象沒有用新的位置創建,或者通過顯式調用它們的析構函數刪除了某些對象,那麼可能存在懸掛指針的風險。