Какой способ удалить указатель: удалить / удалить [] / бесплатно? - PullRequest
1 голос
/ 26 марта 2011

Я реализую стандартную структуру дерева шаблонов, и я столкнулся с небольшой проблемой.

Идея, что каждый узел будет содержать указатель на некоторые данные.Позже, чтобы правильно удалить элемент, мне нужно знать, является ли он одним указателем или указателем на массив.

Внутри моего tree->ReleaseMemory() метода у меня есть этот код:

if (node->_data != NULL)    {

        switch (_destructionMethod){

        case  tree_delete:
            delete  node->_data; break;
        case  tree_deleteList:
            delete [] node->_data; break;
        case  tree_free:
            free(node->_data); break;

    }


}

, где _destructionMethod было установлено во время инициализации узла.Есть ли способ, которым я могу выбрать правильный деструктор, не определяя его в специальной переменной для него во время инициализации?

Спасибо!

Ответы [ 5 ]

4 голосов
/ 26 марта 2011

Первый базовый:

delete используется при выделении памяти с помощью new:

int *p = new int;
int *a = new int[10];
//...
delete p; 
delete []a; //note the difference!

free используется при выделении памяти с помощью malloc:

int *p = (int*)malloc(sizeof(int) * 1);
int *a = (int*)malloc(sizeof(int) * 10);
//...
free(p);
free(a); //no difference!

Теперь ваша проблема:

Есть ли способ выбрать правильный деструктор, не задавая его в специальной переменной для него во время инициализации

Рассмотрим основанный на политике дизайн .Это означает, что вы должны написать allocator, который будет инкапсулировать распределение и освобождение в классе, и последовательно использовать это в вашем коде.

2 голосов
/ 26 марта 2011

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

class destroyable_node
{
    virtual void destroy() = 0;
};

template <typename T> class object_node : public destroyable_node
{
private:
    T * value_;

public:
    // Presumes T is copy-constructable.
    object_node(T value) : value_( new T(value) ) {}

    operator T&() {return value_;}
    operator T const &() const {return value_;}

    void destroy() {delete value_;}
};

template<typename T> class array_node : public destroyable_node
{
private:
    T * value_;

public:
    array_node(T[] value)
        : value_( new T[ sizeof(value)/sizeof(T) ] )
    {
        std::copy(value, value + sizeof(value)/sizeof(T), value_);
    }

    operator T*() {return value_;}
    operator T const *() const {return value_;}

    void destroy() {delete[] value_;}
};

... и т. Д.

2 голосов
/ 26 марта 2011

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

1 голос
/ 26 марта 2011

Не делай этого вообще. Используйте умный указатель, например shared_ptr из C ++ 0x или Boost или, если это не вариант, auto_ptr из C ++. Если у вас может быть более одного объекта, рассмотрите возможность использования std::vector.

Ручное управление ресурсами является грязным и трудно понять правильно.

0 голосов
/ 26 марта 2011

Может быть, лучше разработать реализацию абстрактного интерфейса, используемого вашим контейнером, с тремя конкретными подклассами, которые знают, на какую вещь они ссылаются.Ваш контейнер просто вызовет метод destroy () в базовом классе и позволит производным классам беспокоиться о вызове правильного деструктора.

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