Как освободить память из списка классов - PullRequest
2 голосов
/ 05 апреля 2010

Скажем, у меня есть два класса, созданные work и workItem.

        CWorker *work = new CWorker();
        CWorkItem *workItem = new CWorkItem();

Рабочий класс имеет открытый список m_WorkList, и я добавляю в него рабочий элемент.

work->m_WorkList.push_back(workItem);

Если я просто удалю работу

if(work != NULL)
delete work;

Нужно ли мне перебирать список в деструкторе, как показано ниже? Есть ли лучший способ сделать это? Могу ли я использовать вместо этого ясно?

while(m_WorkList.size())
{
    CWorkItem *workItem = m_WorkList.front();
    m_WorkList.pop_front();
    if(workItem)
        delete workItem;
}

Ответы [ 6 ]

4 голосов
/ 05 апреля 2010

Да, вам нужно delete каждый элемент. Если вы звоните new N раз, то вам также нужно позвонить delete ровно N раз. Нет ярлыка для массового удаления элементов.

Также, когда вы закончите с этим, вам нужно позвонить delete на work.

Вы можете использовать new[] и delete[], если хотите создать массив элементов в куче и одновременно освободить элементы в куче. Но в вашем случае это не то, что вы ищете.

Вы можете посмотреть boost :: shared_ptr , если не хотите вручную выполнять эти вызовы удаления.

3 голосов
/ 05 апреля 2010

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

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

2 голосов
/ 05 апреля 2010

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

struct deleter
{
    template <class T>
    void operator()(const T* ptr) const
    { 
        delete ptr;
    }
};

// Usage
std::for_each(work->m_WorkList.begin(), work->m_WorkList.end(), deleter());
delete work;
2 голосов
/ 05 апреля 2010

Если вы не ведете список workItems где-либо еще, тогда да, вам нужно будет удалить каждый из них по отдельности, прежде чем удалять самого Worker (таким образом, теряя ссылки). Если Worker содержит единственный список, то деконструктор является таким же хорошим местом, как и любой (в противном случае вам нужно будет удалить каждый workItem «вручную» перед вызовом delete на самом Worker)

Однако, если ссылки на workItems существуют где-то еще, вы можете выбрать подходящее время для их удаления, которое может быть или не быть при удалении Worker.

1 голос
/ 05 апреля 2010

используйте boost shared_ptr (который скоро станет стандартом)

  typedef boost::shared_ptr<WorkItem> WorkItemPtr;
  ....
  std::list<WorkItemPtr> list;
  ...
  list.push_back(new WorkItem);

Теперь, когда список будет удален, рабочие элементы будут удалены для вас. Вы можете передавать WorkItemPtrs в своем коде и не беспокоиться о них.

1 голос
/ 05 апреля 2010

Это действительно зависит от владельца, который вы должны решить при создании интерфейса. Скажем, у вас есть метод:

CWorker::AddItem(CWorkItem *workItem)

Вам необходимо указать, кому принадлежит память и для чего ее следует удалить. В зависимости от того, что вы пытаетесь сделать, для вызывающего может иметь смысл владеть им (например, если элементы должны регулярно использоваться совместно с CWorkers), или для CWorker - владеть им (если каждый CWorkItem принадлежит одному CWorker). Тот, кто владеет им, несет ответственность за его удаление.

В первом случае вы можете взять WorkItems как shared_ptrs, чтобы указать, что право собственности распределяется между Workers, и вам не нужно будет выполнять ручное удаление. В последнем случае вы также можете использовать специализированный контейнер, такой как ptr_vector , чтобы избавить от необходимости удаления вручную, но вы также должны заметить, что функция, которой вы управляете памятью.

Также, как примечание, delete является нулевым, поэтому вам не нужны эти операторы if, и pop_back () будет быстрее, чем pop_front ()

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