【问题标题】:How to delete an object in a set如何删除集合中的对象
【发布时间】:2011-08-15 21:15:10
【问题描述】:

在我的 C++ 程序中,我使用 new 在一个函数中创建对象。这些对象被插入到一个集合中。当我想从集合中删除对象时,我在 for 循环中使用迭代器。当我从集合中删除对象时,我仍然需要删除对象以释放其内存,对吗?我尝试使用delete,但后来我收到一个错误,说没有分配被释放的指针。那么如何做到这一点呢?

这是我创建对象然后将其插入集合的代码

set <myObject> myobjectlist;
myObject *myobject = new myObject;
myobjectlist.insert(*myobject);

在另一个函数中,我尝试从集合中移除一个对象,并释放它的内存:

    for (set<myObject>::iterator i = myobjectlist.begin(); i != myobjectlist.end(); i++)
if (i->myObjectID == myObjectID)
{
    myobjectlist.erase(*i);
    delete &i;
    break;
}

如果没有“删除”部分,这可以正常工作。我添加它是因为我认为对象的内存没有被释放。

【问题讨论】:

    标签: c++ pointers object memory delete-operator


    【解决方案1】:

    假设您正在调用集合的erase() 方法,请注意这将为您调用对象的析构函数。在您erase() 您的对象之后,它已经是deleted,因此您第二次尝试手动调用 delete 将失败,因为不再分配指针。

    参考见this

    【讨论】:

    • 根据他的代码 sn-p 这个陈述是误导性的。他的set按值存储对象,所以erase破坏的不是他用new分配的。
    • 不,因为他通过引用删除,事实并非如此。他的集合包含他的原始对象值的副本,然后可以找到该副本。该值从集合中被擦除(并销毁),然后尝试删除迭代器——这将不起作用,因为它不再指向有效块。
    • 他的代码不会尝试删除迭代器,它会尝试删除迭代器的地址(这仍然是一个有效的地址,只是没有一个指向分配了新的东西)。但这不是重点,代码会泄漏原始对象。
    • 重点是——如果没有分配新的东西,你就不能删除它。该集合删除副本,并通过尝试删除迭代器引发错误
    • @Ben,这不是我提出问题的重点。即使我们纠正了这一点,它仍然会泄漏内存。目标是让它运行,还是让它正确?
    【解决方案2】:

    是的,您需要删除您创建的对象。但是,您的集合中的内容不一定是您分配的内容。例如,也许您的集合包含对象值(而不是指针)并且您分配的对象在插入后被泄露。邮政编码。

    编辑: 就是这样。您的集合不存储指针,它存储您正在分配的对象的副本。从擦除循环中删除删除并插入对象,如下所示:

    set <myObject> myobjectlist;
    myobjectlist.insert(myObject());
    

    或者,只需将您的集合设为set&lt;myObject*&gt;

    此外,erase 需要一个迭代器 - 无需取消引用它。

    【讨论】:

    • 进行这些更改会导致 for 循环中的编译错误。应该怎么改?
    • 如果它存储副本,那么创建对象时不使用new可能没问题?
    • 无论哪种方式,您都无法删除您拥有erase()d 的元素。擦除成员调用对象的析构函数,删除将尝试做同样的事情!
    • 正确 - 删除新的和删除的。
    【解决方案3】:

    这是你想要的,假设你需要使用 new 来分配这些对象:

      set <myObject*> myobjectlist;     
      myObject *myobject = new myObject;
      myobjectlist.insert(myobject); //insert the pointer, not the object
    
      for (set<myObject*>::iterator i = myobjectlist.begin(); i != myobjectlist.end(); i++) {
        if ((*i)->myObjectID == myObjectID) {
          myobjectlist.erase(i);
          delete *i;
          break;
        }
      }
    

    【讨论】:

    • @sean,擦除不会增加迭代器。实际上,erase 是按值获取这个参数的,所以它根本不会对你的迭代器对象产生任何影响。
    • 为清楚起见,调用擦除将更改集合,因此使迭代器无效,以便在集合中进一步使用。但是,迭代器本身保持不变,仍可用于检索指向刚刚擦除的对象的指针。
    • 我的困惑是基于 vs2010 的擦除实现 - set::erase 返回 void,但它是通过 _Tree::erase 实现的,它确实返回一个递增的迭代器
    【解决方案4】:

    如果需要指针列表,请使用智能指针列表。 使用标准算法找到正确的项目并将其从列表中删除。

    #include <set>
    #include <boost/shared_ptr.hpp>
    #include <boost/bind.hpp>
    
    using namespace boost;
    
    typedef boost::shared_ptr<MyObject> t_object;
    std::set<t_object> myObjectList;
    myObjectList.insert(t_object(new MyObject));
    
    std::set<t_object>::iterator item = std::find_if(
        myObjectList.begin(), 
        myObjectList.end(), 
        bind(&MyObject::myObjectID, _1)== myObjectID);
    if(item!=myObjectList.end())
        myObjectList.erase(item);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多