2014-09-22 44 views
0

在閱讀放置新操作員時發現以下代碼。刪除內部或外部的位置刪除

#include <iostream> 
using namespace std; 

class MyClass { 

public: 
    // Placement new operator 
    void* operator new (size_t sz, void* v) { 
    cout << "Placement new invoked" << endl; 
    return v; 
    } 

    ~MyClass() { 
    // Cleanup 
    } 
}; 

int main() 
{ 
    // Create a buffer to store the object 
    int buffer[16]; 
    cout << "Starting address of my buffer = " << &buffer << endl; 

    // Create the object. Use placement new 
    MyClass* obj = new (buffer) MyClass(); 
    cout << "Location of my object = " << obj << endl; 

    // Don't delete object created with placement delete 
    // Call the destructor explicitly 
    obj->~MyClass(); 
} 

我不得不刪除其使用放置新創建的對象相關的幾個問題:

  1. 什麼是清理代碼需要在析構函數寫爲這是在被佔領的OBJ 可用內存緩衝存儲器。
  2. 是否需要定義放置刪除,如果是,是否需要在析構函數內或析構函數外。如果它在析構函數外部如何被調用?
+0

你只需要顯式調用析構函數。沒有任何地點刪除。 (但請注意,如果底層緩衝區已分配,則可能需要刪除..) – 2014-09-22 16:25:34

+0

閱讀發佈代碼末尾的兩行註釋 – 2014-09-22 16:26:28

+0

沒有放置 - 刪除 – CashCow 2014-09-22 16:33:54

回答

0

什麼是清理代碼需要在析構函數來寫,以這是在緩衝存儲器佔用的OBJ可用內存

析構函數應該只是做任何的析構函數:清理任何由對象管理的資源。在這種情況下,它不管理任何資源,所以不需要做任何事情。

根據如何分配對象本身的存儲空間,它不應該做任何特殊的事情。必要時管理該存儲是自定義newdelete運營商的工作。

難道不是需要定義位置刪除

號安置新來構建與您所管理自己存儲的對象,這是對自己釋放的存儲你的責任。在這種情況下,存儲是自動的,所以當函數退出時它會自動釋放。就像分配器for placement-new什麼都不做(只是將提供的指針返回到預先分配的存儲)一樣,相應的釋放器也不會做任何事情;所以它不存在。你只需要在你自己處理存儲之前直接調用它的析構函數來銷燬對象。

+0

§18.6.1.3定義了一個全局的'operator delete(void *,void *)';如果 他定義了一個類特定的'operator new(size_t,void *)',那麼在構造函數拋出的情況下,它可能是定義相應的操作符delete''的好形式。如果沒有別的, 將確保刪除指向 對象的指針將找不到全局的'operator delete'(這不是 可能適用於他的位置'operator new')。 – 2014-09-22 17:20:48

+0

@JamesKanze,對於上面的代碼,你可以定義運算符刪除。如果我調用刪除obj,而沒有定義運算符刪除,那會有什麼影響? – user3665615 2014-09-22 17:46:13

+0

@Mike,考慮上面的整數私有數據成員的例子,然後MyClass * obj = new(buffer)MyClass();將在緩衝區中爲obj分配4字節的內存。現在可以解釋如何從緩衝區中刪除obj內存,以便緩衝區保持其舊狀態。 – user3665615 2014-09-22 18:16:08

0

定期new做了兩兩件事:

  1. 分配內存爲對象
  2. 構造你的對象在內存空間。

安置new意味着你管理其中一個,而另一個管理像以前一樣。

  1. 你分配/爲你的對象
  2. 構造函數被調用的內存空間提供的內存。

相反的是delete其經常delete執行以下操作:

  1. 調用該對象的析構函數,以清理
  2. 免費這是分配給它的內存。

請注意,由於顯而易見的原因,它們以相反的順序完成。您不能釋放包含有關需要清理的信息的內存,直到您已完成使用該內存。而在建設中,你需要先掌握內存。

在你所說的放置刪除中,但實際上與放置放置相反,你需要執行銷燬的第一步,但不是第二步。因此,你可以調用對象的析構函數,然後你可以釋放它使用的內存/用於別的東西。

使用placement new最常見的例子是std::vector,它需要一個連續的數據緩衝區,並且可以讓你提前預定(如果你不這樣做,它可能會爲你做)。該部分分配內存,但不構建它中的對象。因此,稍後構建時,將使用新的放置。

+0

實際上,放置新可能意味着兩件不同的事情。在通用意義上,這意味着您可以將其他參數傳遞給'operator new'函數;類型和它們的含義取決於你。該術語也可以用於新的位置的一個特定變體,其中有一個額外的'void *'參數,它剛剛返回。 – 2014-09-22 17:37:57

0

首先要問的是:你想做什麼?如果 定義了班級中的新佈置操作員,那麼這是 唯一的操作員新操作,當您編寫new MyClass時將會找到;你必須總是指定額外的參數。在 幾乎所有情況下,你定義一個類特定的operator new,你也應該定義一個類特定的operator delete; 否則當您編寫delete p時,全局operator delete函數將被稱爲 ,而這通常不起作用。

如果你的目標是系統需要 分配和初始化的分離,這就是爲什麼要定義 成員運營商新的,那麼你可以提供一個無操作operator delete;如果該類的構造函數可以拋出,那麼 也會提供一個位置操作符刪除,因爲這是 如果新對象的構造函數通過異常退出 ,將會調用什麼。但是,沒有其他方式可以調用它。 當提供新的安置操作員時,您必須提供 默認的操作員刪除,這是正確的;並且當 爲同一類型提供幾個新操作符時,您需要 記住某個被調用的每個分配,在 爲了在非放置操作符刪除中分派。

順便說一下,剛剛分配的緩衝區作爲一個局部變量 不保證足夠的定向的任何東西,但 聲明緩衝區類型。

編輯:

的需要以何種爲operator delete功能(必須是會員)只是一個例子:

void operator delete(void* p) {} 
void operator delete(void* p, void*) {}