【问题标题】:vector freeing issue compared to array与数组相比,向量释放问题
【发布时间】:2011-04-01 14:56:24
【问题描述】:

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

     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 类的指针是本地对象的地址还是动态分配的,这很困难。 但是,只要开发人员确信所有内容都是动态分配的,他就可以使用释放功能(如果提供)。

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

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

vector 中是否有任何函数可以释放所有内部对象?

【问题讨论】:

  • 我可以评论一下,写Test* a = ...delete[] a; 更清楚,在第一种情况下,类型是一个指向测试的指针(实际上是一个数组,但总的来说它在我的将类型写成一体的意见:Class* someObject),在第二种情况下,您在a 上使用运算符delete[],而不是[]a 上的运算符delete,这几乎不一样。

标签: c++


【解决方案1】:

你的例子根本不做同样的事情。

如果你想要这个数组代码的向量等价物:

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[]

但是,如果您的容器存储了指向动态分配对象的指针,那么您有责任在某个时候删除这些对象。无论您的容器是数组还是向量,都是如此。

【讨论】:

  • @rubenvb:它删除了数组。但是如果数组存储了指针,它不会删除那些指针指向的内容。
  • @jalf:啊哈,我现在明白了。不使用数组的另一个原因。
  • @jalf:我在下面的行 a[0] = t1 中遇到错误;因为我没有在 Test 类中重载赋值运算符。在这种情况下如何定义赋值运算符?
  • @jalf: 同样如果 a[0] 和 t1 都相同,那么这样做是否正确? for(int i = 0; i
  • @bjskishore123:对不起,我打错了。 a 的类型应该是 Test**,因为它是一个指向 Test pointers 范围的指针,就像您创建了一个 Test 指针向量一样。现在应该修好了。对于您的第二条评论,是的,这是正确的。 a[0]t1 都指向同一个对象,所以无论你调用它们中的哪一个都没有关系。
【解决方案2】:

不,没有办法要求充满指针的std::vector 自动在其所有元素上调用delete

但是,还有其他第三方容器可以通过在指针从向量中删除或向量解构时自动删除指针来简化此类事情。例如,boost::ptr_vector and friends

【讨论】:

    【解决方案3】:

    简短的回答是否定的。 C++ 不提供指针向量释放函数。

    长答案是双重的:

    1. 使用智能指针,忘记释放(c++0x 中的shared_ptrunique_ptr 可以满足您的大部分需求)。或者,使用 Tyler 建议的 Boost ptr_vector。

    2. delete 容器中的每个项目编写一个简单的通用算法并不难(使用带有迭代器的模板)。

    (警告:未经测试的代码,没有时间检查它)

    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 );
    }
    

    【讨论】:

      【解决方案4】:

      不,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&lt;Foo*&gt;,你可以这样做:

      #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,它们是拥有指针所有权并在容器销毁时自动为您执行删除操作的容器。

      【讨论】:

        【解决方案5】:

        我之前问过同样的问题,有人建议我使用 Boost 库,你会发现很好的提示 here 或者你可以简单地理解智能指针如下:

        您将拥有一个 智能指针 的向量,而不是指针向量,因为您将创建的每个新指针都会自行删除,而无需担心。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-06-04
          • 2012-05-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多