【问题标题】:Vector of pointers element deletion指针元素删除向量
【发布时间】:2014-04-14 15:26:30
【问题描述】:

我有一个指针向量,我想删除一个条目。删除条目后,我检查向量的大小并且它没有减小。我应该做额外的事情吗?

printf("size of vector before %d \n", m_obj.size());
for(std::vector<object*>::iterator it = m_obj.begin(); it != m_obj.end(); ++it)
{
  if((*it)->m_id == p_id)
  {
     delete *it;
  }
}

printf("size of vector after %d \n", m_obj.size());

【问题讨论】:

  • 使用std::remove_if,以及智能指针,这样您就不必手动释放它们。
  • 你只是删除了实际的指针,你没有从向量中删除任何东西。在循环之后,你有一个指针向量,其中一些指针现在是无效的。
  • 您正在删除向量中的指针指向的内存。您没有删除向量中的条目。

标签: c++ vector delete-operator


【解决方案1】:

您对delete *it 的调用仅删除了向量中该条目所指向的对象。您不修改向量本身。

要同时从向量中删除元素,请使用erase 方法:

 delete *it;
 it = m_obj.erase(it);

请注意,擦除会使当前迭代器无效,因此您可能希望将 erase 调用的返回值分配给您的 it 变量。但是,请注意不要在循环中擦除多个条目时意外跳过元素。返回的迭代器将指向被删除的元素之后,并将通过for 循环再次递增。

摆脱这个问题的最简单方法是使用STL algorithm 来删除元素。如果条目还拥有其指针对象的所有权,则此方法效果最佳,因此您可能需要考虑使用smart pointers 的向量(如建议的in the comments),因此您完全不必担心显式调用delete .

【讨论】:

    【解决方案2】:
               +----------+         +-------------+
               | object * |-------->| heap memory |
               +----------+         +-------------+
    it-------->| object * |-------->| heap memory |
               +----------+         +-------------+
               | object * |-------->| heap memory |
               +----------+         +-------------+
               | object * |-------->| heap memory |
               +----------+         +-------------+
    

    delete *it之后:

               +----------+         +-------------+
               | object * |-------->| heap memory |
               +----------+         +-------------+
    it-------->| object * |-------->
               +----------+         +-------------+
               | object * |-------->| heap memory |
               +----------+         +-------------+
               | object * |-------->| heap memory |
               +----------+         +-------------+
    

    您还需要以某种方式擦除向量中的指针元素。请记住,您不能在迭代期间执行erase(it),因为它会使您的迭代器无效。

    【讨论】:

      【解决方案3】:

      您只是在释放指针下分配的内存。您不会删除指针本身。

      调用delete后,将指针的值设置为NULL。在你的 for 循环之后使用 std::remove_if 对元素进行 NULL 检查。

      【讨论】:

        【解决方案4】:

        删除对象不会从向量中删除指向它的指针,它只会释放指针指向的内存。释放元素后,您需要在向量上显式调用erase

        【讨论】:

        • m_obj.erase(it);//像这样?
        • @AvbAvb 精确。请记住,从向量中擦除可能会使迭代器无效,因此循环可能会中断。您需要在循环完成后擦除元素。
        • @IvayloStrandjev 不完全是。请参阅 ComicSansMS 的答案。
        • @ooga 是的,这是另一种选择。
        【解决方案5】:

        拥有一个拥有 原始指针的STL容器(例如std::vector)通常是个坏主意。这可能是 leaktrocity 的来源:例如如果在某处抛出异常,则调用向量析构函数,但这将不会删除原始拥有的指针!所以他们的相关资源被泄露了。
        此外,您必须提供明确的清理代码等。

        您可能想要使用std::vector&lt;Object&gt;智能指针std::vector,例如vector&lt;shared_ptr&lt;Object&gt;&gt;vector&lt;unique_ptr&lt;Object&gt;&gt;(由于移动语义,后者从 C++11 开始可用,如果 vector 是对象的 唯一 所有者,并且没有共享所有权)。

        您可能还想使用 算法,例如 remove_if()。特别是,要从 vector 中删除满足某些精确条件的项目,您可能需要使用所谓的 erase-remove idiom

        // Use a vector of *smart pointers* (shared_ptr or unique_ptr).
        typedef std::shared_ptr<Object> ObjectPtr;
        std::vector<ObjectPtr> v;
        
        ...
        ...
        
        // Use the erase-remove idiom to erase items satisfying a particular condition.
        v.erase( std::remove_if(v.begin(), v.end(), [&](const ObjectPtr & p) { 
            return p->m_id == deleteId; // Erasing condition 
        }), v.end());
        

        为了使代码更清晰(特别是如果你不知道/识别擦除删除习语),可以编写一个小辅助函数来实现这个习语:

        // Helper function to implement the erase-remove idiom for std::vector.
        template <typename T, typename Predicate>
        void erase_if(std::vector<T>& v, Predicate p) {
            v.erase(std::remove_if(v.begin(), v.end(), p), v.end());
        }
        

        然后这样称呼它:

        // Simplified code: just pass the vector 'v' and the erasing condition
        // (in this case using a simple lambda).
        // Uses the erase-remove idiom under the hood.
        //
        erase_if(v, [&](const ObjectPtr & p) { return p->m_id == deleteId; });
        

        请注意,由于使用了remove_if 算法 和擦除删除习语,您的代码的语义级别 提高了:您没有阅读显式 for 循环和迭代器不再递增;您只需阅读清楚的代码intent,即擦除满足给定条件的项目。


        PS:您可能还想阅读:"How do I erase elements from STL containers?"

        【讨论】:

          猜你喜欢
          • 2013-09-24
          • 2012-08-12
          • 2015-08-09
          • 1970-01-01
          • 2011-03-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多