2010-01-06 48 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对象的指针数组。