【问题标题】:Should I delete vector<string>?我应该删除向量<string> 吗?
【发布时间】:2009-06-14 19:45:25
【问题描述】:

在过去的几天里,我痛苦地学习了很多关于 C++ 编程的知识。
我喜欢它:)
我知道我应该释放内存——“每个 malloc=free”或“每个 new=delete”的黄金规则现在存在于我的世界中,但我将它们用于相当简单的对象。
向量呢?尽我所能,我都在使用 vector.clear() 但这显然还不够,因为我有大量的内存泄漏。
你能指导我如何处理这个东西吗?

*编辑
谢谢,您的 cmets 让我想到了这个应用程序的算法,我将能够完全消除向量。 :O
抱歉 - 我开始在这里解释我的用例,然后我发现了我真正需要的东西。就像你连续 3 天每天 18 小时编写代码一样:| *编辑 2
这太疯狂了。通过对代码的微小更改,我将内存使用量从 2x130 mb(不断增长)减少到 2x 13.5mb,大小不变。谢谢你让我以另一种方式思考这个问题。

顺便说一句。这种自我代码审查有一个名字——有人记得吗?当你问任何人(甚至是你的母亲或狗)并开始解释你的问题时——突然间你自己解决了这个 5 小时的问题,只是试图从另一个角度看待它,或者只是试图总结它是什么所有关于。我经常发现自己被抓住了......

【问题讨论】:

  • 由于您是内存管理的新手,也许您可​​以解释一下您是如何知道自己遇到内存泄漏的。一些衡量内存泄漏的方法并不能真正反映正在发生的事情。
  • 您可能想发布一些示例代码,说明您如何使用矢量类。例如,您是否有指向动态创建对象的指针向量?
  • 好吧,我只是看到我的应用程序的执行导致越来越多的内存占用。我正在执行相当简单的操作(在 2 个进程中生成 md5 哈希,与 mpcih2 绑定),对于我的测试,它恰好是 2500 万次操作。一个进程向其他数据包(字符串)发送数据,第二个进程为此计算哈希值。在执行结束时,我占用了 2x 130 mb。这太正常了。
  • 仅晚了 9 年,但是将您的问题解释给人们/事物作为找出您自己的解决方案的一种方法有很多名称。我最常听到它被称为“灯柱”或“橡皮鸭”,但我敢肯定它还有其他流行的名字。
  • Rubberducking 确实是这样。

标签: c++ memory-management


【解决方案1】:

规则是当你清除一个对象向量时,每个元素的析构函数都会被调用。另一方面,如果你有一个指针向量,vector::clear() 不会对它们调用delete,你必须自己删除它们。

因此,如果您只有一个字符串向量,而不是指向字符串的指针,那么您的内存泄漏肯定是由其他原因引起的。

【讨论】:

  • 这是否普遍适用?如果我有一个将std:vector 作为其属性之一的类,当类被销毁时,C++ 会调用该析构函数吗?
  • 是的。当一个对象被销毁时,它的所有数据成员的析构函数都会被调用。但正如我所说,请注意您在向量中存储的内容。如果它是对象的向量,则对象将与向量一起被销毁。如果是指针向量,那得自己删除。
【解决方案2】:

调用v.clear()会销毁当前保存在v中的所有对象,但不会释放内存(假设向量很快会被再次填充)。

如果真要释放内存,成语是

vector<string>().swap(v);

这将创建一个新的(临时)向量并将其内容与v 交换。然后临时向量被销毁,同时释放内存。

【讨论】:

  • 现在我明白了这背后的意图,但我觉得这很尴尬。它会和 v.swap(vector()) 一样吗?
  • 这可能看起来很尴尬,但这是减少v.capacity() 的惯用方式。你的 sn-p 不会编译,因为 vector&lt;string&gt;() 是一个右值,不能绑定到非常量引用。
  • 澄清一下:在 a.swap(b) 中,a 和 b 不相等。成员交换有一个参数,一个非常量引用。您可以调用临时的非常量成员函数,因此在 a.swap(b) 中,a 可以是临时的。但是 b 绑定到一个非常量引用,不能是临时的。
【解决方案3】:

您不需要这样做。 std::string 会自行清理,因此字符串不是您的问题。请记住,您没有使用new,因此您不必使用delete

您可能应该了解RAII - 它使分配和解除分配变得更加简单。这样可以避免内存泄漏。

【讨论】:

    【解决方案4】:

    保证从 STL 容器中删除元素会调用这些元素的析构函数。 然而,如果你有一个 pointer-to-T 类型的容器,那么你仍然必须自己释放指向的内存(在这种情况下,指针的“析构函数”被调用,这是一个无操作)。

    如果您不想在这种情况下手动管理内存,请考虑使用smart-pointer solutionpointer container

    【讨论】:

      【解决方案5】:

      向量(与所有标准容器一样)拥有其中的对象。
      所以它负责销毁它们。

      注意:如果向量包含指针,则它拥有指针(而不是指针指向的位置)。所以这些需要删除。但还有更简单的方法。

      您可以使用智能指针向量。事实上,你应该对几乎所有事情都使用某种形式的智能指针。如果您使用指针,您可能仍在像 C 程序员一样编程。

      所以:

      std::vector<int>    data; // clear is fine.
      
      std::vector<int*>   data1; // Now things need to be deleted.
      // alternative 1:
      std::vector<boost::shared_ptr<int> >  data2; // The shared pointer will auto
                                                   // delete the pointer.
      // alternative 2:
      boost::ptr_vector<int>  data3;               // Here the container knows that
                                                   // it is holding pointers and will
                                                   // auto de-reference them when you
                                                   // its members.
      

      但听起来你需要开始考虑学习智能指针。

      int*  x = new int(5);
      // Do stuff.
      *x = 8;
      delete x;
      
      // --- Instead use a smart pointer:
      std::auto_ptr<int>  x(new int(5));
      // Do stuff.
      *x = 8;
      // No delete (the auto ptr handles it.
      

      【讨论】:

        【解决方案6】:

        如果你有一个向量并且它超出了范围,那么向量中的所有对象都会被销毁。除非您想转储内容并重用向量,否则实际上不需要调用 clear()。

        但是,如果您有任何机会使用向量之类的东西,那么所指向对象的析构函数将不会被调用,因为向量析构函数不遵循指针表示的间接。

        说了这么多,你真的确认你有真正的内存泄漏并且它们是由向量中的数据引起的吗?

        【讨论】:

          【解决方案7】:

          给出一个用例。字符串上的析构函数被vector::clear 调用。我的朋友,你的问题出在其他地方。

          也可以看看:

          Does std::vector.clear() do delete (free memory) on each element?

          【讨论】:

            【解决方案8】:

            按照 rlbond 的建议,使用 RAII。

            永远不要将 new 和 delete 调用放入主代码流中,这是一个很好的经验法则。始终尝试将它们放入对象中,以便对象析构函数可以释放需要释放的内容。通过这种方式,您无需记住调用 delete 并且它使您的代码异常安全(假设您使对象的操作异常安全)。

            例如,如果您有一个指向 STL 字符串或 C 样式字符数组的指针向量,请将其放入 StringContainer(使用更好的名称)并让 StringContainer 保存一个向量,并在 StringContainer 析构函数中运行一个 for 循环删除向量中的每个字符串。

            您可以将 StringContainer 中的向量设为公共成员并直接对其进行处理,但更好的设计是将其设为私有或受保护并添加一些成员函数来管理 string* 向量。

            因此,您的 C++ 主程序永远不会在任何地方看到新的或删除的内容。相反,它应该有很多堆栈分配的对象,auto_ptrs 和 shared_ptrs。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-07-29
              • 2018-11-28
              • 2016-05-20
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多