2010-07-23 8 views
1

У меня есть следующий класс:Удаление вложенной структуры с указателями void как членами?

class Stack { 
    struct Link { 
    void* data; 
    Link* next; 
    void initialize(void* dat, Link* nxt); 
    }* head; 
public: 
    void initialize(); 
    void push(void* dat); 
    void* peek(); 
    void* pop(); 
    void cleanup(); 
}; 

Метод pop является:

void* Stack::pop() { 
    if(head == 0) return 0; 
    void* result = head->data; 
    Link* oldHead = head; 
    head = head->next; 
    delete oldHead; 
    return result; 
} 

oldHead является указателем на struct Link, который имеет пустое указатель в качестве члена. Итак, удалив oldHead Я неявно удаляю этот указатель void, не так ли?

Я читаю «Мышление на C++» Брюса Эккеля, и он говорит, что удаление указателей void не очищает вещи должным образом, потому что delete должен знать тип указателя.

Этот код неявно удаляет указатель void data, так: Может ли кто-нибудь объяснить, почему этот (неявный) способ удаления указателя void отличается от удаления с помощью delete <void pointer>?

+0

Почему, по-вашему, это другое? –

+2

Что касается мышления на C++, не используйте void *. В этом примере шаблоны будут работать отлично. –

+0

Дэвид, я предположил, что это было другое, поскольку автор сначала предупреждает об использовании delete на указателях void, а затем использует приведенный выше код. –

ответ

2

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

struct foo 
{ 
    void* bar; 
}; 

Всякий раз, когда foo заканчивает свою жизнь, bar просто перестает существовать тоже. Так что если у вас есть:

{ 
    foo f = { new int; } 
} 

Вы просочились, поскольку new int никогда не удаляется.Точно так же, когда вы делаете:

{ 
    foo* f = new foo; 
    f->bar = new int; 
    delete f; 
} 

Вы все еще протекла, так как, когда delete f запускается, вы просто конец жизни, что f указывает на (так же, как то, что произошло автоматически выше), эрго bar просто перестает существуют, и new int не удаляется.

Подводя итог, когда срок службы объекта заканчивается, delete is не вызывает члены, являющиеся указателем.

Так что, когда вы звоните удалить на Link, это та же ситуация, как bar в foo выше: вы deleteing память для Link вызывающего data остановить существующие, но на самом деле не удаляя то, что это указывает на.

+0

Спасибо всем за ваши ответы. –

0

Удаляем Link, что void * пространство памяти не удаляется. Вам нужно определить деструктор, который удаляет выделенную память. Каждому новому нужно удалить. Примером этого для Link-struct будет добавление деструктора, который удаляет data. Если ваше предположение будет правильным, то также будет удален next, что приведет к удалению всего связанного списка, что было бы ужасным поведением.

Вызов удаления по указателю вызовет деструктор указанного типа. Если этот тип не имеет деструктора, такой деструктор не будет вызван. Это относится к указателю void, который не имеет деструктора. В случае наследования деструктор всегда должен быть виртуальным, чтобы вызываемый деструктор вызывал наименьший класс в иерархии. Память будет корректно свободной, даже если вы нарисуете указатели на неправильные типы - это просто, что деструктор будет вызван неправильно.

0

«Я неявно удаляю этот указатель на пустоту, верно?»

Ну, вы удаляете указатель, когда вы удаляете oldHead. Вы не удаляете и не освобождаете его цели, что вам кажется очень нужным, и это происходит, когда вы вызываете delete на указатель.

(Чтобы понять, почему это так, считайте, что вы можете определить структуру с указателем void*, который указывает на что-то вне структуры. Вы не хотите, чтобы цель была освобождена только потому, что структура была удалена.)

+0

Он возвращает цель, поэтому он не должен удалять ее в первую очередь. Из-за указателей void класс стека не знает, что такое цель. Управление сохраненными значениями полностью зависит от пользователя. (В C++ такие классы обычно пишутся с помощью шаблонов, а указатели void не используются, если нет веской причины - совместимость со старым кодом C и т. Д.) – UncleBens

0

Одна проблемы с удалением пустого указателя происходит, когда вы направляете на что-то с деструктором:

#include <iostream> 

struct foo 
{ 
    ~foo() { std::cout << "important work" << std::endl; } 
}; 

int main() 
{ 
    foo *f = new foo; 

    void *v = f; 

    delete v; 
} 

Если запустить пример кода выше, вы увидите, что деструктор не вызываются.