【问题标题】:Memory Leaks without calling clear() on C++ STL container objects没有在 C++ STL 容器对象上调用 clear() 的内存泄漏
【发布时间】:2015-08-04 09:16:56
【问题描述】:

假设我有一个类 Foo 定义如下。 如果我在 ~Foo() 中没有 bars.clear(),会不会导致内存泄漏? 我想知道这一点,因为 bars 是一个对象字段(不是指针字段),所以当 ~Foo() 被调用时, std::vector 的析构函数 应该被自动调用,所以我想知道 std::vector 的析构函数是否会透明地调用 .clear()

    class Foo
    {
      private:
        std::vector<Bar*> bars;//object field

      ...
    };


    Foo::~Foo
    {
      //bars.clear();
    }

【问题讨论】:

  • clear 在这里没有任何区别。
  • 谁拥有Bars?
  • @KarolyHorvath:当然是调酒师。
  • @MatteoItalia:很可能,他是个普通员工
  • 我建议改用简单的std::vector&lt;Bar&gt;,或者如果你真的需要指针std::vector&lt;std::shared_ptr&lt;Bar&gt;&gt;std::vector&lt;std::unique_ptr&lt;Bar&gt;&gt;,这样你就不必关心任何资源管理。

标签: c++ memory-leaks stl


【解决方案1】:

clear()只是将向量重置为0大小。它对delete没有任何作用,如果需要删除向量bars中的Bar*,你必须自己做。

【讨论】:

    【解决方案2】:

    std::vector::clear() 删除std::vector 中的对象并将其std::vector::size() 更改为零。如果您创建std::vector,RAII 将负责资源释放过程,但您必须等到超出向量范围。如果在超出范围之前,您需要清理您的向量,您可以使用std::vector::clear()

    但在您的特殊情况下,您将指向 std::vector 内的对象的指针,因此 RAII 确实删除了指针,但忽略了指向指针的对象。因此,您必须在超出范围和 RAII 变为活动之前或在调用 std::vector::clear() 之前对指向指针的对象进行自己的清理工作@

    【讨论】:

      【解决方案3】:

      如果您希望通过调用 clear() 方法来保护自己免受内存泄漏,那么我不得不让您失望。如果您使用带有指针的向量,则需要执行以下操作:

      std::vector<Bar*> bars;
      bars.push_back(new Bar());
      // some work with bars
      //  ....
      // end of bars usage:
      // (probably inside ~Foo() )
      for(int i=0; i<bars.size(); i++) delete bars[i];
      

      根据您的经验水平和您的具体用例,您可能会更好地使用:

         std::vector<Bar> bars;
      

      如果你想知道 std::vector<...>::clear() 方法是否是从向量的析构函数中调用的,那么答案是:也许但不一定,而且确实没有无论如何都重要。

      如果您真的很好奇,您可以通过查看向量容器模板的头文件来检查容器类的析构函数的作用。用户是否可以看到 std 库对象的实现细节以及有多少实现细节高度依赖于您正在运行的系统。在工作中,我碰巧在 Solaris 10 机器上工作。这些机器上的标准库是 Hewlett Packard anno 1994 的实现,其中向量模板使用的许多实际代码仍然可见:

      ~vector ()
      { 
        __destroy(__start, __finish); 
        __value_alloc_type va(__end_of_storage);
        va.deallocate(__start,__end_of_storage.data()-__start);
      }
      void clear()
      {
        erase(begin(),end());
      }
      iterator erase (iterator first, iterator last)
      {
        iterator i = copy(last, end(), first);
        iterator tmp = __finish;
        __finish = __finish - (last - first); 
        __destroy(i, tmp);
        return first;
      }
      

      【讨论】:

      猜你喜欢
      • 2015-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-13
      • 1970-01-01
      • 2014-09-22
      相关资源
      最近更新 更多