2012-01-07 38 views
1

考慮下面的代碼指點指點連續內存

struct foo 
{ 
    const int txt_len; 
    const int num_len; 

    char * txt; 
    int * num; 

    foo(int tl, int nl): txt_len(tl), num_len(nl) 
    { 
     char * tmp = new char[txt_len * sizeof(char) + num_len * sizeof(int)]; 

     txt = new (tmp) char [txt_len * sizeof(char)]; 
     num = new (tmp + txt_len * sizeof(char)) int[num_len * sizeof(int)]; 

     // is this the same as above? 
     // txt = tmp;         
     // num = (int *) (tmp + txt_len * sizeof(char)); 
    } 

    ~foo() 
    { 
     delete[] txt; // is this the right way to free the memory? 
    } 
}; 

我想*txt*num是連續的,是最好的方式做到這一點?

放置新指針和指針算術是否有區別?我應該使用哪一個?

+0

我不知道你可以在現有的內存上使用新的方式。爲你+1。 – rsaxvc 2012-01-07 04:27:36

+1

如果不理解你爲什麼要連續記憶,很難給你一個有用的答案。這實際上取決於你打算如何處理它。 (例如,你是否打算取消引用它的指針?如果是這樣,什麼類型?你想要一個正常的結構將有間距?或者你想它打包?)上面的代碼是非法的,你不能通過安置新一個不對齊的指針。 – 2012-01-07 04:31:48

+3

首先放置'int',因爲它具有更嚴格的對齊要求。並且'sizeof(char)'保證完全是'1'。 – 2012-01-07 04:37:17

回答

1

如果您想要連續的內存塊,則必須通過一次調用operator new[]malloc()或類似的函數將其分配。多次調用這些函數並不能保證任何分配塊的連續性。您可以分配一個大塊,然後根據需要從中分割出部分。

你應該deletefree()所有塊先前newmalloc()分配,否則會導致內存泄漏,可能使你的程序不穩定(它將無法在某個時刻分配更多的內存),並會對內存不必要的壓力操作系統,可能會減慢其他程序或使其不穩定。

然而,放置新內容實際上並沒有分配任何內存。它只是在指定的位置構造一個對象,所以不需要釋放該內存兩次。

我在代碼中看到的一個問題是它沒有對齊整數。在某些平臺上,讀取或寫入內存中大於1字節的整數必須對齊,如果不是,則可以從/向錯誤位置讀取/寫入值,或者獲取導致程序終止的CPU異常。 x86在這方面非常寬容,不會介意,但可能會降低您的性能。

+0

我不確定你的意思。除了對齊問題之外,您似乎確認OP代碼是正確的。這是正確的嗎? – 2012-01-07 04:45:40

+0

@AaronMcDaid:是的。 – 2012-01-07 05:10:27

+0

好的,對不起。當我讀到「......你必須通過一個單獨的呼叫給operator new [] ...」來分配它時,「我認爲你的意思是你認爲OP使用了多個呼叫。但是很顯然你明白只有一個OP的調用真的分配新的內存。謝謝你的澄清。 – 2012-01-07 05:12:23

0

這與使用POD類型相同。你的刪除很好。
但是,正如David的評論所述,您需要考慮對齊問題。

+3

如果txt_len是3並且整數必須在他的平臺上以4字節邊界對齊,該怎麼辦? – 2012-01-07 04:33:08

+0

@david:好點 – Dani 2012-01-07 04:36:48

0

當你想在一些預分配的內存塊上調用類/結構的構造函數時,Placement new主要用到。

但是對於本機類型,使用放置新指針算術沒有什麼不同。

如果我錯了,請糾正我。

0

如果txt和num始終指向int和char,其他內置類型或其他不需要構造的類型,則不會。你不需要新的位置。

另一方面,如果您要將其中的一個更改爲需要構建的類,即將txt更改爲鍵入std :: string,則需要使用placement new。

Placement new允許您調用構造函數,如果願意,可以構建該地址處的對象。內置的類型有默認的構造函數,如果你不初始化,它什麼也不做。

在這兩種情況下,您都需要進行指針算術,只是將答案存儲在指針中的一種方式,另一種方式是將答案傳遞給放置位置new,然後將其返回給您存儲在指針中,然後調用構造函數。

1

由於對齊問題,您需要首先放置整型數據。但是我們不能這樣做delete num[],因爲類型是錯誤的 - 在刪除之前它必須被轉換爲char*

char * tmp = new char[num_len * sizeof(int) + txt_len * sizeof(char)]; 

num = new (tmp) int[num_len]; 
txt = new (tmp + num_len * sizeof(int)) char [txt_len]; 

(這使得自由使用的是sizeof(char)==1事實)

你也許會做delete[] num,但num是int*型的,並且它new「編爲char*。所以你需要做;

delete[] (char*) num;