2011-11-02 22 views
5

我試圖在C++中創建一個類型不可知的向量,該向量由兩個事物來區分。首先,它在對象本身中分配內存,至少直到某個點,而不是在堆上維護實際的對象數組。其次,它不能使用C++的複製/分配構造函數,這似乎會減慢代碼的速度並且不是必需的。關於移動/複製C++對象實例

查看我在計算機上維護的代碼庫時,發現LLVM代碼庫中的類非常完美地描述了我正在尋找的內容:SmallVector.h。對於C++來說相對陌生,我不完全確定爲什麼會做出一些設計決策。例如,爲什麼數組按照U而不是T分配?評論給出了一條線索:

如果T有ctor或dtor,我們不希望它自動運行,所以我們需要將空間表示爲別的東西。一個字符數組可能很好,但可能沒有足夠的對齊。相反,我們使用空間的一些聯合實例來保證最大的對齊。

U,當然,是指下列工會:

union U { 
    double D; 
    long double LD; 
    long long L; 
    void *P; 
} FirstEl; 

所以,我想,這裏是我真正的問題:爲什麼分配的T數組意味着構造函數/析構函數叫什麼名字?有沒有什麼辦法可以移動C++對象實例,即在向量內外移動,而不調用這些構造函數/析構函數?我想我可以使用LLVM的SmallVector實現,但我討厭使用代碼而不理解它。

最佳, 杜安

+0

'C++的複製/分配構造函數,它似乎會減慢代碼...'它使_correct_代碼,因爲它們是必需的。有幾個類會在它們被memcopied時崩潰,並且_not_沒有默認的構造函數。 –

回答

3

你應該看看標準庫分配器背後的基本機制,它可以解決許多你可能遇到的問題!

以下是基本分配原則。我們分開內存分配和對象構造。最大的障礙是,當你觀察到,內存應該正確的對象對齊:

// getting memory 
void * p = malloc(1000); // version 1, system's allocator 
char q[1000];    // automatic array, this is also memory :-) 

// constructing an object 
T * m_x1 = ::new (p) T; // default-initialized 
T * m_x2 = ::new (q) T(); // value-initialized 
T * m_x3 = ::new (q + sizeof(T)) T(1, 'a'); // some specific constructor 

// destroying the objects: 
m_x1->~T(); 
m_x2->~T(); 
m_x3->~T(); 

做你心目中,你可以採取的字符數組q,我使用並使其成員你的班級。也就是說,班級總是帶着一些記憶來構建物體。

實際的對象構造是用全局位置新表達式完成的。回想一下,這樣構建的對象必須手動銷燬(這將是你的責任)。

標準庫分配器的功能非常類似。

分離內存分配和對象構造是任何類型的高級內存管理,負責擁有類的核心。

請注意,一旦對象在特定地址構建,不得移動內存在左右。這個對象很可能取決於它自己在內存中的位置!移動物體的唯一有效方法是複製/移動 - 構建新的對象。

1

爲什麼分配T的陣列意味着構造函數/析構函數叫什麼名字?

因爲這就是標準的要求。分配數組T意味着也初始化其每個元素。請注意,在C++ 11中,對於char的對齊限制已經更改,因此現在「一個char數組很好用」。

是否有任何方法可以在不調用這些構造函數/析構函數的情況下移動C++對象實例,即移入和移出矢量?

是的,通過移動構造函數/賦值運算符,這也是C++ 11的新增功能。有一個用於C++ 03的模擬器庫,也支持移動支持容器,位於Boost

+1

注意:_動態分配的char數組適用於所有對齊。一個自動的字符數組可能不會。 –

0

C++ 11也有移動語義。如果你在你的類中實現一個移動構造函數(比如Foo),std :: vector將會更好。