2011-09-18 121 views
3
分配內存

有這樣的代碼:動態堆棧

#include <iostream> 

int main() 
{ 
    int a; 
    int* p = new (&a) int(2); 
    std::cout << a << std::endl; 
    // delete p; error BLOCK TYPE IS INVALID 
    std::cin.get(); 
    return 0; 
} 

的輸出是:

2 

爲什麼可以對堆棧動態分配存儲器? (我認爲這個堆是正確的地方)。而且,爲什麼刪除操作符在這種情況下返回錯誤,但是新的操作員工作?

+1

也就是說**安置新** –

+0

你正在做新的佈局,所以要重複使用'了'的內存來代替對了進去。 –

+1

它不是真正的動態,因爲你必須使用的最大空間是'sizeof(int)' – James

回答

7
int* p = new (&a) int(2); 

這被稱爲placement-new。它不分配內存。它在a的相同內存中構造該對象。在放置新對象時,用戶指定new運算符構造對象的內存區域。在上面的代碼中,通過在new關鍵字後面寫入(&a)表達式來指定內存區域。由於&a不是一個動態分配的內存,你不能delete

delete p; //runtime-error 

它將給運行時錯誤,它會嘗試刪除內存中的變量a駐留的位置。

但是,如果您動態分配內存,那麼您可以刪除它。讓我們假設,A是一些類,那麼你應該這樣做:

char *buffer = new char[sizeof(A)]; //allocate memory of sizeof(A); 

///ASSUMPTION: the buffer is properly align as required by the type A 
//use placement-new to construct an object at the specified memory region 
A *pA = new (buffer) A(/*..parameters..*/); 

//... 

//incorrect way to delete the memory! 
//delete pA; //incorrect 

//before deleting the memory you should be calling the destructor explicitly as 
pA->~A(); //call the destructor explicitly - must do it 

//now deallocate the memory as 
delete []buffer; 

這是最簡單的例子投放新這也解釋了語法只。但這個故事並沒有在這裏結束。它是一個開始,並使其正常工作,由buffer指向的內存必須正確對齊對象類型,並在上面的示例中,我只是假設如此。在真實的代碼中,你不能做出這樣危險的假設。現在讀這常見問題解答:

3

這就是所謂的placement newhttp://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10

您可以將地址選擇通過新的,它只會調用對象的構造函數(如果有的話)。由於沒有分配內存,因此通過刪除來釋放內存將會出錯。只需調用對象的析構函數(如果有的話)就完成了。

8

這是使用放置新語法。放置new不會分配內存,相反,它是在特定位置構建對象的一種方法。在這個例子中,內存來自堆棧。它不需要。刪除有問題,因爲你沒有新的內存。

有辦法從堆棧(alloca)動態分配內存,但這不是在這裏發生的事情。

2

C++分離了內存分配對象生存期的概念。與C相比,這可能是該語言最重要的「新」方面之一。在C中,沒有這種區別,因爲變量完全由其內存決定,而在C++中,對象具有更抽象的「狀態」概念,與基礎內存不同。

讓我們看看內存第一:

{ 
    char buf[100]; // automatic allocation, scoped lifetime 
} 

{ 
    void * p = std::malloc(100);  // dynamic allocation, manually managed 
    void * q = ::operator new(100); // essentially identical 

    // ... 

    ::operator delete(q);    // manual deallocation 
    std::free(p);      // ditto 
} 

在另一方面,對象的一生是一個單獨的話題:

{ 
    Foo x; // automatic storage, scoped lifetime. 
       // Implies automatic memory allocation for sizeof(Foo) bytes. 
} 

{ 
    Foo * px = ::new Foo;  // dynamic storage, manual lifetime, 
           // implies dynamic allocation via ::operator new() 

    Foo * py = ::new (q) Foo; // dynamic storage and manual lifetime, uses memory at q 

    // ... 

    delete px;     // destroy object _and_ deallocate memory 

    py->~Foo();    // destroy object. Memory was never our business to start with. 
} 

正如你可以看到,內存的分離並且對象的生命週期增加了很多靈活性:我們可以讓動態對象生活在自動內存中,或者自己負責分配並重復使用內存來重複構建對象。標準newdelete表達式結合了分配和構造,但這只是最常用操作的捷徑。原則上,你完全可以自由處理內存和對象的生命週期。

該想法支持分配器的概念,這是C++標準庫中的核心概念。