2010-01-06 72 views
6

我有一個abstractBase類和Derived類。刪除運算符和數組?

int main() 
{ 
    Base *arrayPtr[3]; 

    for (int i = 0; i < 3; i++) 
    { 
    arrayPtr[i] = new Derived(); 
    } 

    //some functions here 

    delete[] arrayPtr; 

    return 0; 
} 

我不知道如何使用刪除操作符。如果我刪除了如上所示的基類指針數組,這個調用派生類對象析構函數並清理內存?

回答

10

你必須遍歷您的陣列的每個人的元素,delete然後在陣列上調用delete [](如果它已使用new[]動態分配)。

在您的示例代碼中,數組被分配在堆棧上,因此您不能在其上調用delete []

還要確保你的Base類有一個virtual析構函數。

參考:When should my destructor be virtual

+0

+1虛擬析構點 – 2010-01-06 11:29:28

+7

不需要在數組上調用delete [],它是不是'newed'。 – fretje 2010-01-06 11:30:43

+0

是的,當你編寫你的評論時,我正在編輯我的答案,thx – 2010-01-06 11:31:54

10

不,你必須在數組中顯式地刪除每個項目:

for (int i = 0; i < 3; ++i) 
{ 
    delete arrayPtr[i]; 
} 
+0

@Roger我看不到刪除[] – 2010-01-06 11:30:06

+0

@Roger:意識到我的第一篇文章......已經被編輯出來了,但是非常感謝;) – fretje 2010-01-06 11:31:16

+0

詹姆斯:它在第一個5分鐘內被編輯出來。 – 2010-01-06 11:33:04

2

而應該做的:

for (int = i; i < 3; i++) 
{ 
    delete arrayPtr[i]; 
} 

,你不應該做delete[] arrayPtr;如你想免費/刪除堆棧中分配arrayPtr

要考慮的另一件事是使用指針的std::vector而不是數組。如果您使用的是實現TR1的編譯器,那麼您也可以使用std::vectorstd::tr1::shared_ptr而不是原始指針,並且您不必擔心自己刪除這些對象。

例子:

{ 
    std::vector< std::tr1::shared_ptr<Base> > objects; 
    for (int i=0; i < 3; ++i) 
    { 
     objects.push_back(std::tr1::shared_ptr<Base>(new Derived())); 
    } 
} // here, once "objects" exit scope, all of your Derived objects are nicely deleted 
+0

Shared_ptr <>不是一切的答案!指針不共享一個開始。 boost :: ptr_vector <>可能是更好的選擇。 – 2010-01-06 17:02:15

+0

同意,只是在暗示「最少的罪惡」,從某種意義上說,我已經在我的macbook上使用gcc創建了shared_ptr,並且使用boost :: ptr_vector我需要在項目中拖動boost,這可能並非必要。 – Dmitry 2010-01-06 17:33:59

+0

@Martin York:'shared_ptr <>'不是所有事物的答案,但它是大多數指針問題的一個安全答案。我通常會使用它,除非我有理由使用不同的東西,並且在一般情況下可以合理地使用它。 – 2010-01-07 17:29:29

0

確保Base有一個虛擬析構函數。然後像fretje outlined一樣,刪除數組中的每個元素,然後刪除該數組。你應該使用std::vector作爲數組。這就是說,你應該真的使用這種東西的容器。 (所以你不會意外地不刪除所有的元素,如果拋出異常肯定會出現這種情況!)Boost有such a library

+0

雖然「你應該使用容器」絕對是一個頂級的建議,不知怎的,它不應該被過快拋出。我的意思是1)通過手動理解發生了什麼,然後2)在生產代碼中利用像STL和Boost這樣的實體庫。否則,是否有將圖書館提供的容器和其他工具視爲只有黑盒的傾向?你怎麼看? – 2010-01-06 11:39:42

+0

Gregory:不同意。在某種程度上,你應該明白髮生了什麼(可能),但我不知道應該以什麼順序(我曾經同意你的觀點)。你應該知道malloc如何工作,然後纔可以調用new?在使用dynamic_cast之前,你應該瞭解vtable是如何工作的(然後*然後*找出這不是實現的保證部分)?兩者都沒有。也就是說,你應該總是知道去哪裏查找你需要的信息,或者與誰交談等。 – 2010-01-06 11:46:54

+0

@Roger我明白你的觀點。以您的示例爲例,您不需要知道堆內存分配的實現細節,但仍然可以瞭解堆和堆棧之間的區別。你不需要知道vtable是如何實現的,你仍然必須知道調用一個虛擬方法是間接的。最後算法和數據結構是黃金:即使使用std :: vector或std :: list實現,你也必須知道連續數組和列表概念之間的區別,否則從長遠來看,你只是缺乏線索:) – 2010-01-06 11:55:08

1

您必須單獨刪除數組的成員。你還必須確保你的基類有一個虛擬析構函數。您可能還想考慮將它作爲智能指針的數組(或更好的還是std :: vector),例如boost :: shared_ptr。

1

不,你不能那樣做。正如其他人建議你必須通過每個項目並刪除它。記住這是一個非常簡單的規則。如果您使用new分配然後使用delete,並且如果您使用new[]然後使用delete[]

0

不,這不完全是你想要的。

有兩點需要注意這裏:

  1. 的語法,如果你動態地分配陣列delete[] arrayPtr使用,像這樣:但是

    arrayPtr = new (Base *)[mylength]; 
    

    在你的情況,你有一個靜態分配的數組,所以不需要刪除它。你這樣做,不過,需要刪除單個元素的數組:

    for (int = i; i < 3; i++) 
        delete arrayPtr[i]; 
    
  2. 第二點,你需要的是使類的析構函數Base虛擬照顧:

    class Base 
    { 
        virtual ~Base(); 
        /* ... */ 
    }; 
    

    這可以確保當您調用Base *上的刪除時,實際上指向Derived,將調用Derived的析構函數,而不僅僅是Base的析構函數。

1

注意什麼是不存在的:

int main() { 
    boost::ptr_vector<Base> v; 
    for (int i = 0; i < 3; i++) v.push_back(new Derived()); 
    // some functions here, using v[0] through v[2] 
} 

檢查Boost's pointer containers出來。

1

運算符刪除必須與該指針上的operator new匹配,如果它被分配了new[],則必須調用delete[],反之亦然;

int* pInt = new int; 
delete pInt; OK 
delete [] pInt; WRONG 

int[] pIntArr = new int[3]; 
delete [] pIntArr; OK 
delete pIntArr; WRONG 

在你的情況下還有其他的錯誤 - 你正試圖delete分配在堆棧上。那不行。

在這種特殊情況下,您必須單獨刪除每個指針。

1

你有什麼是未定義的行爲 - 一個錯誤。每次致電new需要與delete匹配;每個致電new[]的電話都需要與delete[]匹配。兩者是分開的,不能混合使用。

在您發佈的代碼中,您有一個指向堆棧中分配的基數的指針數組。然後你在堆棧上分配的數組上調用delete[] - 你不能那樣做。您只能在new[]的堆上分配一個數組delete[]

對於分配給new的每個元素,您需要致電delete - 或者最好使用容器類(如std::vector)來代替使​​用數組。

0

你是混合範式 - 數組刪除操作符被設計爲釋放由數組new運算符分配的內存,但是你將數組作爲指針數組分配給數組,然後爲每個數組分配一個對象會員。在你的代碼中,你需要遍歷數組。

使用數組新的運營商,你會聲明是這樣的:

Base *array; 
array = new Base[3]; 
/* do stuff */ 
delete[] array; 

這對於分配三個對象一個連續的內存區域 - 注意,你已經有了基本對象的數組,而不是指向Base對象的指針數組。