开发者

Free memory after remove_if

In the following example I remove from list some elements in the range for which the application of pr2 to it return true.

m_list.remove_if(pr2(*tmp_list));

It seems to me it is necessary to delete this objects, which was removed above, becase when I create it I use "new" (new CRectangle()). How I can do this? I don't know which (and how much) elements will be remove after remove_if.

// test_cconnection.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <conio.h>
#include <iostream>
#include <list>
#include <algorithm>

using namespace std;

class CDrawObject
{
public:
    virtual ~CDrawObject()
    {
        cout << "Drop CDrawObject: " << id_ << endl;
    }
    int getId() const
    {
        return id_;
    }
    virtual void draw()
    {
    }
protected:
    static int id;
    int id_;
};

class CRectangle : public CDrawObject
{
public:
    CRectangle()
    {
        id_ = id++;
    }
    ~CRectangle()
    {
        cout << "Drop CRectangle: " << id_ << endl;
    }
    virtual void draw()
    {
        cout << "CRectangle, id: " << id_ << endl;
    }
};

class CMarker : public CDrawObject
{
    CDrawObject* obj;
public:
    CMarker(CDrawObject* obj_)
    {
        obj = obj_;     
    }
    ~CMarker()
    {
        cout << "Delete marker of object with id: " << obj->getId() << endl;
    }
    CDrawObject* getObject() const
    {
        return obj;
    }
    virtual void draw()
    {
        cout << "CMarker of oject with id: " << obj->getId() << endl;
    }
};

int CDrawObject::id = 0;

// predicate for compare objects with int id
class pr : public std::unary_function<CDrawObject*, bool>
{
private:
    int id_; 
public: 
    pr(int id): id_(id) {}  
    bool operator()(CDrawObject* arg) const 
    { 
        return (arg->getId() == id_); 
    } 
};

// predicate for check objects with type CMarker and
// compare with CDrawObject* obj
class pr2 : public std::unary_function<CDrawObject*, bool>
{
private:
    CDrawObject* obj_; 
public: 
    pr2(CDrawObject* obj)
    {
        obj_ = obj;
    } 
    bool operator()(CDrawObject* arg) const 
    { 
        if (dynamic_cast<CMarker*>(arg))
            return ((dynamic_cast<CMarker*>(arg))->getObject() == obj_); 
    } 
};

int _tmain(int argc, _TCHAR* argv[])
{
    list<CDrawObject*> m_list;
    list<CDrawObject*>::iterator i_list, tmp_list;

    m_list.push_back(new CRectangle());
    tmp_list = m_list.end();
    m_list.push_back(new CMarker(*--tmp_list));
    m_list.push_back(new CMarker(*tmp_list));

    m_list.push_back(new CRectangle());
    tmp_list = m_list.end();
    m_list.push_back(new CMarker(*--tmp_list));

    m_list.push_back(new CRectangle());
    tmp_list = m_list.end();
    m_list.push_back(new CMarker(*--tmp_list));
    m_list.push_back(new CMarker(*tmp_list));

    // print on screen items of m_list
    for (i_list = m_list.begin(); i_list != m_list.end(); ++i_list)
        (*i_list)->draw();

    // get an iterator to the first element in the range with id_ = 2
    tmp_list = find_if(m_list.begin(), m_list.end(), pr(2));

    if (tmp_list !=  m_list.end())
    {
        // remove from list all elements with type CMarker 
        // and CDrawObject = tmp_list       
        m_list.remove_if(pr2(*tmp_list));
    }

    cout << endl << "--------" << endl;

    // print on screen items of m_list
    for (i_list =开发者_如何学Go m_list.begin(); i_list != m_list.end(); ++i_list)
     (*i_list)->draw();


    _getch();
    return 0;
}


Well you could:

HACKISH: delete the object in the predicate.

ANNOYING: Stay away from remove_if and implement everything it does on your own except add the delete.

BETTER: use RAII objects rather than raw pointers. Some sort of smart ptr in other words.


The way it's implemented at the moment, you won't be able to delete the memory that you allocated for those objects. In general, it takes some extra effort to perform memory cleanup when you have containers of pointers to dynamically allocated memory. Here's one way to do it:

// Assume there's a predicate function called ShouldRemove(int value);
list<int> my_list;

// initialization...

for (list<int>::iterator itr = my_list.begin(); itr != my_list.end(); ) {
    if (ShouldRemove(**itr)) {
        delete *itr;
        itr = my_list.erase(itr);
    } else {
        ++itr;
    }
}

But as Noah Roberts pointed out, this is all much easier to deal with if you store your pointers as smart pointers that clean up after themselves.


Standalone remove_if never resizes a collection and returns an iterator pointing to the first object for which predicate is false. It is therefore more appropriate for your task.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜