2011-01-13 7 views
0

В следующем примере я удаляю из списка некоторые элементы в диапазоне, для которого приложение pr2 возвращает true.Свободная память после remove_if

m_list.remove_if(pr2(*tmp_list)); 

Мне кажется, необходимо удалить эти объекты, которые были удалены выше, Becase когда я создаю его я использую «новый» (новый 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; 
} 
+0

Ew. Это ужасно. –

ответ

4

Ну вы можете:

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

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

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

+2

+1. Здесь применяется разделение ответственности: очистка выделения памяти в основном является отдельной «ответственностью» за обновление содержимого контейнера. –

1

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

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

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

1

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

Смежные вопросы