2014-07-10 125 views
0

如何從以下代碼靜態初始化my_collestions?我將有5個Collection S和不同數量的Buff S IN他們每個人,例如:C++靜態初始化:摺疊結構

// 2 [buff], [buff] 
// 3 [buff], [buff], [buff] 


struct Buff 
{ 
    int len; 
    const char *ptr; 
} 

struct Collection 
{ 
    int num; 
    Buff buffers[]; // length is unknown here 
} 


static const Collection my_collestions[]; // i need to initialize this 
+0

您應該向Collection中添加一個構造函數,該構造函數將#個緩衝區作爲參數,然後在構造函數中初始化緩衝區。 – Steger

+0

@Steger我不需要在那個結構中做任何改變,所以我不希望結構在運行時自行構造。 – pavelkolodin

+0

但是你需要一個可變數量的緩衝區,對吧?所以你可以爲Collection定義一個構造函數,或者在Collection中創建一個模板。 – Steger

回答

1

使用矢量代替陣列。

如您所定義的,sizeof(Collection)不包含數組的空間(因爲您沒有提供任何長度),就好像數組是空的一樣。所以如果你想分配收集物品,你應該自己分配空間,計算所需的正確尺寸。

這意味着不可能創建一個Collection數組,因爲這些對象不會爲其緩衝區保留空間。

的中間解決辦法是改用陣列的指針:

struct Collection { 
    int num; 
    Buff *buffers; 
}; 

在這種情況下緩存器可以在構造進行分配。

+0

謝謝。我有同樣的想法) – pavelkolodin

-2

也許是這樣的?
是:這利用了未知行爲的黑魔法。
然而: AFAIK這是要求問題靜態執行此操作的唯一方法。
問:這是一個好主意還是應該以不同的方式完成?
- 答:這取決於情況。

struct Buff { 
    int   len; 
    char const *ptr; 
    }; 

    struct Collection { 
    int num; 
    Buff buffers[1]; 
    }; 

    template <unsigned S> 
    struct CollectionSize : public Collection { 
    private: 
    Buff extraspace[t-1]; 
    }; 

    static const Collection &my_collestions[] = { 
    CollectionSize<1>(), // add more constructor arguments so you can initialize the base class. the object is const so this is your last chance to do so. 
    CollectionSize<2>(), 
    CollectionSize<3>(), 
    CollectionSize<4>(), 
    CollectionSize<5>() 
    }; 

說明:

關鍵是你拋開通過非類型模板的派生類的額外空間,但你通過基類數組訪問它。你過度閱讀下一個對象,但內存將在那裏,是的,這是未定義的行爲,但實際上這將工作。你也可以使數組成爲const references而不是對象本身或指針。您需要引用或指針,以便可以將對象切片到其基類,因爲該數組需要是同類型的。這非常重要,因爲C++標準對於臨時對象的const引用有特殊的規則(也就是說,只要引用在附近時它們就會一直存在),這就避免了你必須調用new來動態分配CollectionSize對象。

回顧的關鍵組件:由常量引用常量引用堅持圍繞引用

  • 無名的臨時對象(仍然有效的對象,還是分配,與析構函數還未調用)只要引用在const範圍內(在這種情況下,靜態引用在範圍內,直到程序退出)(不能寫入它們)。
  • 製作派生模板類型的對象意味着您可以在對象內部爲基類分配更多空間(這由標準未定義,但在實際中適用於所有編譯器AFAIK)。
  • 由於在實踐中編譯器定義了一些沒有虛擬指針的單繼承類的對象佈局,所以已知派生類的內存直接位於派生類的最後一個成員數組之後。訪問這個內存不是標準定義的,但會在實踐中使用。

編輯:
我已經收到了這個答案了一些批評,所以我張貼一些額外的意見,以解決它

我開頭這個答案的事實,它可能涉足不確定的,但很OK-的實踐。這就是編譯器是如何做到的!因此,現實的只有兩件事情,我們擔心是:

  1. 對象佈局,並確保有足夠的內存,以便陣列訪問。雖然在C++中沒有定義對象佈局,但是編譯器供應商在做這件事時做得非常好,並且它是一致的,至少對於沒有虛擬指針的類的單一繼承是一致的。
    • 會員將按順序排列。
    • 派生類將在基類之後的內存中。 所以,即使有填充也沒關係,因爲在對象的末尾至少需要這麼多的空間,並且可以通過基類以一致的方式操縱它。
  2. C++中的規則約爲當您訪問您不擁有的內存時會發生什麼。這個數組技巧在C中是非常常見的事情。通常它採用一個簡單結構的形式,其中一個數組作爲大小爲0或1的元素的最後一個成員,程序員調用malloc來獲得較大的大小,然後通過訪問結束內存結構的數組。

在實際的實施和我自己的經驗,我從來沒有遇到過任何一個行爲不如預期的情況。這對程序員來說是最好的選擇嗎?很可能它不是,但它又取決於它。也許STL向量,或者甚至指針的額外的間接層都不是某個隨機低端系統的選項。也許這些對象確實需要爲了優雅的代碼而放入數組中。

無論如何,問題的提出方式是如何使這樣的結構靜態初始化,而不是天氣或不是一個好主意。 AFAIK這是做到這一點的最佳解決方案。然而,更好地實現這一點的其他解決方案當然受到歡迎

+0

在非標準的佈局對象中,你不能保證編譯器如何佈局對象。 –