2014-02-21 46 views
3

我读关于如何实现一个ArrayList我的数据结构的书,我对擦除功能如下代码:为什么在此代码中调用析构函数?

template<typename T> 
ArrayList<T>::~ArrayList() { 


delete [] dynArr; 


} 

我:

template <typename T> 
void ArrayList<T>::erase(int index) { 

    //Delete the element whose index is "index" 
    //Throw illegalIndex exception if no such element 
    checkIndex(index); 



    std::copy(dynArr+ index + 1, dynArr + listSize, dynArr + index); 

    dynArr[--listSize].~T(); //invoke destructor 


} 

的析构函数的定义对于那里到底发生了什么感到困惑。是不是只有在需要删除整个数组时需要删除的析构函数?

+1

您可以调用dynArr的元素的析构函数而不是类的析构函数ArrayList – Felix

+0

请注意,在现实世界中几乎不应该看到这种类型的代码。让编译器在99.99%的时间内为你调用析构函数。 – jia103

回答

2

T的析构函数(的ArrayList<T>未析构函数),并因为使用特殊的placement new operator

其中在堆上一个预先分配的阵列上创建,而不是单独类型T的对象,所以当一个人很可能被删除没有必要释放任何内存,但你想调用析构函数,所以状态将被清除

放置new运算符允许构造给定内存地址的对象。这允许库(比如std :: vector)为将来的构造分配一块内存。并且使用在该块上的特定位置放置新运算符构建类实例:void* operator new (std::size_t size, void* ptr) throw();

但是,当您要删除对象时,您不能delete因为它不拥有内存,但仍然调用析构函数它会清理自己的状态。 AFAIK这是唯一的使用情况是适当的调用析构函数直接

编辑 说明发表评论为什么调用析构函数的最后一个对象上,而不是指数:

STD: :副本将“复制”的使用他们的赋值运算符还挺像这样的对象:

template<class InputIterator, class OutputIterator> 
OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result) 
{ 
    while (first!=last) { 
     *result = *first; 
     ++result; ++first; 
    } 
    return result; 
} 

所以运营商=物体将被称为很多次。 位置索引处的对象将被索引+ 1处的对象覆盖。您期望适当的分配实施既释放自己的资源,又准确地复制目标资源。 当你完成这个操作时,你会得到一个正确的数组,其中最后两个元素是相互精确的副本,并且你使用析构函数来清理最后一个元素。

注意:这样做的性能大概可以考虑改进C++ 11移动语义,而不是性病::复制(如升压移动算法boost::move

NOTE2:如果你持有一个指针,指向一个元素列表在一个位置>索引它会在这种改变后指向错误的元素。

+0

嗯..所以析构函数只是照顾在我选择在函数中删除索引的元素?因为当我读取dynArr [ - listSize]时,它使我认为它正在销毁dynArr [ - listSize]上的元素,但这与销毁作为参数的索引处的元素不同。不应该析构函数首先销毁元素,然后使用副本将元素移动一个位置?@edsh – FrostyStraw

+0

请参阅编辑,以了解为什么代码在“去除”最后一个元素而不是索引处的元素中是正确的。 但是,如果有人持有一个指向ArrayList中的元素的指针,那么在此更改之后它将是错误的元素 – odedsh

相关问题