【问题标题】:Is it a memory leak to push_back a pointer into a vector of pointers?将指针推回指针向量是否存在内存泄漏?
【发布时间】:2012-09-08 19:28:15
【问题描述】:

在我的课堂上,我有一个成员变量std::vector<node*> children

以下类成员函数是否会造成内存泄漏?

//adds a child node
{
    node* child = new node("blah","blah","blah");
    child->Set_Parent(this);
    children.push_back(child);  //<- Is this ok?
}

向量复制了指针,我有两个指向同一内存的指针, 然后原始指针超出范围,对吗?

这可能简单明了,但我想确认一下我的假设。
谢谢

【问题讨论】:

  • 我建议你研究一下智能指针,比如std::shared_ptr
  • @JoachimPileborg:在这种情况下,您甚至可以使用std::unique_ptr,因为std::vector 支持移动语义。
  • 如果节点总是应该有父节点,你可以让它成为构造函数的一部分。那么你只需要children.push_back(new node("blah","blah","blah"), this);
  • @ddriver 哦,鬼鬼祟祟!我会在构建根目录时传入 nullptr

标签: c++ pointers memory-leaks vector c++11


【解决方案1】:

这还不是泄漏……还没有。但是,如果 vector 超出范围,或者您 erasepop_back 或执行其他从向量中删除元素的操作,而没有先 deleteing 您要删除的元素,您将拥有一个漏到手上。

正确的做法是从使用vector&lt;node *&gt; 更改为vector&lt;unique_ptr&lt;node&gt;&gt;。您的代码将更改为

//adds a child node
{
    node* child = new node("blah","blah","blah");
    child->Set_Parent(this);
    children.push_back(std::unique_ptr<node>(child));
}

如果可以使用 Boost,请使用 boost::ptr_vector&lt;node&gt;

【讨论】:

  • 是的,我可以避免使用原始指针,但它们我不会得到跟踪内存泄漏的做法! :) 不知道 boost 有这样的课程!谢谢
  • 最后一行可以是children.emplace_back(child);
【解决方案2】:

如果在调用包含向量的析构函数的类时忘记释放子节点,这只是内存泄漏。

【讨论】:

  • 太棒了!谢谢。是的,我的析构函数循环遍历向量,并删除每个指针。我发现没有理由将它们设置为 null,因为指针很快也会消失。
【解决方案3】:

这不是内存泄漏。您仍然在向量中有一个指针,您将能够在需要时释放内存。

【讨论】:

    【解决方案4】:

    当向量超出范围时,它的析构函数不会破坏指向的对象。它破坏了指针——它什么都不做。

    您的代码通过new 创建了该对象。您的代码负责删除该对象。如果你不这样做,你就有泄漏。如果你这样做很早,即在从向量中删除指针之前,你会遇到更大的问题。

    【讨论】:

      【解决方案5】:

      假设 children 是一个类成员,您只需删除类解构器上向量中的所有项目。

      struct Foo{};
      
      class Bar
      {
      public:
          Bar(){};
          ~Bar()
          {
              for( vector<Foo*>::iterator it = children.begin(); it != children.end(); ++it )
              {
                  SAFE_DELETE( (*it) ); //use your own macro/template or use delete if you don't have one
                  delete (*it);
                  (*it) = NULL;
              }
          }
          vector<Foo*>children;
      }
      
      Foo* p = new Foo();
      children.push_back( p );
      

      如果您改为使用vector&lt;Foo&gt;child,则向量上的每个push_back 都会创建要存储的原始对象的副本,但由于您使用的是指针,在这种情况下由new 在堆上分配没有创建对象副本,只是存储了指向长期对象的指针,这意味着是的,您必须稍后将其删除。

      【讨论】:

      • 我没听错,你认为删除时不需要设置一个指向NULL的指针吗? safe_delete 多年来一直是已知的宏/模板,其目的是安全地删除堆分配的项目。我建议您阅读 David Mayhew 和 Scott Meyers 的有效/更有效的 c++。
      • 我不是反对者,但这很愚蠢。 SAFE_DELETE 不安全;它所做的只是在调用delete 之前检查指针是否为空。删除空指针并没有错。不需要那个测试;不需要使用SAFE_DELETE 而只是使用delete。为了使SAFE_DELETE 真正安全,它必须以某种方式在调用delete 之前检查一个非空指针是否真的被分配了new。它不会那样做。删除后也没有理由将指针设置为NULL;我们在析构函数中。
      • 问题是SAFE_DELETE既不安全也没有必要。现在我是反对者之一。
      • 如果您需要在拥有它们的对象的析构函数中将指针设置为 null 以避免双重删除,您会遇到更大的问题。基本上,您的对象没有明确定义的生命周期或所有权,而不是治愈它,您隐藏了症状。 (有人提到这个类违反了三规则吗?)
      • 在处理内存泄漏时,怎么可能有人引用三法则呢?处理内存泄漏的那个东西..针对内存泄漏?增值税 IZ ZIS
      猜你喜欢
      • 2019-04-18
      • 1970-01-01
      • 1970-01-01
      • 2013-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多