Свободная память после удаления - PullRequest
0 голосов
/ 14 января 2011

В следующем примере я удаляю из списка некоторые элементы в диапазоне, для которых применение pr2 к нему возвращает true.

m_list.remove_if(pr2(*tmp_list));

Мне кажется, необходимо удалить эти объекты, которые былиудалены выше, потому что при создании я использую «новый» (новый CRectangle ()).Как я могу это сделать?Я не знаю, какие (и сколько) элементы будут удалены после 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 = m_list.begin(); i_list != m_list.end(); ++i_list)
     (*i_list)->draw();


    _getch();
    return 0;
}

Ответы [ 3 ]

4 голосов
/ 14 января 2011

Ну, вы могли бы:

HACKISH: удалить объект в предикате.

Раздражает: держитесь подальше от remove_if и реализуйте все, что он делает самостоятельно, кроме добавления удаления.

ЛУЧШЕ: используйте RAII-объекты, а не сырые указатели. Какой-то умный птр другими словами.

1 голос
/ 14 января 2011

Автономный remove_if никогда не изменяет размер коллекции и возвращает итератор, указывающий на первый объект, для которого предикат имеет значение false.Поэтому он больше подходит для вашей задачи.

1 голос
/ 14 января 2011

Как это реализовано на данный момент, вы не сможете удалить память, выделенную для этих объектов.В целом, для очистки памяти требуются дополнительные усилия, когда у вас есть контейнеры с указателями для динамически выделяемой памяти.Вот один из способов сделать это:

// 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;
    }
}

Но, как отметил Ноа Робертс, с этим гораздо проще справиться, если вы храните свои указатели как умные указатели, которые убирают за собой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...