与数组相比,矢量释放问题如何?

3
我将动态分配的类指针存储在向量中,如下所示:

我将动态分配的类指针存储在向量中,如下所示。

     vector<Test *> v;
    Test *t1 = new Test;
    Test *t2 = new Test;
    v.push_back(t1);
    v.push_back(t2);

现在,如果我需要释放Test对象,我必须遍历整个向量并逐个释放,然后进行清除。
for(int i = 0; i<v.size(); i++)
     {
         delete v[i];
     }
     v.clear();

在vector中有没有释放所有内部对象的函数。该函数应调用每个对象的Test类析构函数。 我理解Vector类很难确定指针是局部对象的地址还是动态分配的地址。 但是,只要开发人员确信所有对象都是动态分配的,他就可以使用提供的释放函数。

虽然vector被视为高级数组,但在数组中释放对象要容易得多,如下所示。

Test  *a = new Test[2];
delete []a;

有没有vector中释放所有内部对象的函数?

我可以评论一下,更清晰的写法是Test* a = ...delete[] a;, 在第一种情况下,类型是指向Test的指针(实际上是一个数组,但总的来说,在我看来将类型写成一个整体会更好:Class* someObject),而在第二种情况下,你正在使用delete[]运算符删除a,而不是对[]a使用delete运算符,这两者并不相同。 - rubenvb
5个回答

4

你的示例完全没有做同样的事情。

如果您想要这个数组代码的向量等效代码:

Test  *a = new Test[2];
delete []a;

这很简单

std::vector<Test> a(2);

如果你有一个指向动态分配对象的指针向量,你需要删除每个对象,就像你的例子中所示:
for(int i = 0; i<v.size(); i++)
 {
     delete v[i];
 }

但对于数组来说也是一样的:

Test *t1 = new Test;
Test *t2 = new Test;
Test **a = new Test*[2];
a[0] = t1;
a[1] = t2;

也必须使用这样的循环删除:

for(int i = 0; i<2; i++)
 {
     delete a[i];
 }
delete[] a;

在第一种情况下,你有两个对象存储在某种容器中。这个容器可以是向量或数组。
在两种情况下,因为对象直接存储在容器中,它们的析构函数在容器被销毁时被调用。你不需要做任何事情来销毁或删除单个成员,你只需要销毁容器(在堆栈分配的向量中更简单,你甚至不需要调用delete[])。
但是,如果你的容器存储指向动态分配对象的指针,则你有责任在某个时候删除这些对象。而且无论你的容器是数组还是向量,这都是真实的。

它删除数组。但如果数组存储指针,它不会删除这些指针所指向的内容。 - jalf
@jalf:啊哈,我现在明白了。不使用数组的另一个原因。 - rubenvb
@jalf: 我在下面这行代码中遇到了一个错误: a[0] = t1; 因为我没有在Test类中重载赋值运算符。 你如何在这种情况下定义赋值运算符? - bjskishore123
@jalf:如果a [0]和t1都相同,像下面这样做是否正确? for(int i = 0; i<2; i++) { delete a[i]; } delete[] a; - bjskishore123
@bjskishore123:抱歉,我打错了。a的类型应该是Test **,因为它是指向一系列Test *指针的指针,就像你创建了一个Test指针的向量一样。现在应该已经修复了。对于您的第二个评论,是的,那是正确的。a[0]t1都指向同一个对象,所以无论你在哪个上调用delete都没有关系。 - jalf

2
简短的回答是不行。C++没有提供指向vector释放内存的函数。
长的回答有两个方面:
1. 使用智能指针,忘记释放(在c++0x中有shared_ptr或unique_ptr可以满足大多数需求)。或者像Tyler建议的那样使用Boost ptr_vector。
2. 编写一个简单的通用算法来删除容器中的每个项(使用迭代器模板)。
(警告:未经测试的代码,无法检查)
template<class It>
void delete_clear_ptr_cont( const It &beginIt, const It &endIt )
{
    for( auto it = beginIt; it != endIt; ++it )
    {
        delete it;
    }
    erase( beginIt, endIt );
}

2
不,没有办法请求一个充满指针的std::vector自动调用delete来删除所有元素。然而,有一些第三方容器可以使这种情况更容易,当指针从向量中移除或向量被销毁时,它们会自动删除指针。例如,boost::ptr_vector和相关容器

1

不,vector 不知道它可能被实例化为指针。即使它知道,也有一些情况下你并不拥有这些指针,也不想要删除行为。

在大多数情况下,我们只需使用智能指针的向量,如 shared_ptr。然而,有时候 shared_ptr 并不适用。对于这些情况,我们有一个类似于这样的函数对象:

#include <functional>

template<typename T>
struct PointerDelete : public std::unary_function<T*, T*>
{
   T* operator()(T*& p) const
   {
      delete p;
      return 0;
   }
};

假设您有一个vector<Foo*>,则可以执行以下任一操作:

#include <algorithm>

std::for_each(v.begin(), v.end(), PointerDelete<Foo>());
// or
std::transform(v.begin(), v.end(), v.begin(), PointerDelete<Foo>());

如果你可以使用boost库,还有ptr_containers,它们是容器,拥有指针并在容器销毁时自动为你执行删除操作。

0

我之前问过同样的问题,建议使用Boost库,你可以在这里找到很好的提示,或者简单地理解智能指针如下:

不要使用指针向量,而是使用智能指针向量,因为每个新的指针都会自动删除,无需担心。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接