2013-03-14 47 views
2

У меня есть вопрос об удалении динамического массива указателей в C++. Представим себе, что у нас есть следующая ситуация:Удаление динамического массива указателей в C++

int n; 
scanf("%d", &n); 
Node **array1 = new Node*[n]; 
/* ... */ 

Узел - определенная структура, определенная заранее. Предположим, что после выделения с помощью нового оператора мы изменим содержимое массива1 (но мы ничего не удалим!). Каков правильный способ удаления массива 1 и всего его содержимого, если есть возможность повторных указателей в массиве (без сортировки или вставки в набор в линейном времени)?

+0

Являются ли указатели в массиве выделены на кучу? Если это так, вы можете добавить счетчик ссылок к узлу или, возможно, иметь другой массив, который содержит только уникальные указатели на выделенные узлы. – Pete

+3

Почему этот помеченный C++? если вы используете C++, просто используйте для этого векторы. – none

+0

Вы хотите изменить значение 'array1' или указатели внутри него? Вы не показываете, как создается содержимое 'array1' в коде. –

ответ

3

Использование этого распределения:

Node **array1 = new Node*[n]; 

Содержания array1 является неопределенной. Каждый элемент является Node*, и поскольку память не инициализирована, значение может быть любым.

Выделение массива указателей не построить объекты заостренного класса.

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

Так, чтобы ответить на ваш вопрос, правильный способ удаления array1 является

delete[] array1; 

Однако, обратите внимание, что это не результата в деструкторах вызываются для каждого Node* - вы должны иметь дело с тем, что вы положили в массив до вы удаляете массив.

EDIT: Я был смущен оригинальным вопрос, который упоминается «изменить значение» в массиве, как будто не было допустимого значения в массиве, как выделено в вашем примере.

BUT ... теперь, когда я понимаю, что вы хотите позже отслеживать указатели на удаление, возможно, вы можете просто создать другой массив для этой цели, где каждый указатель существует только один раз. Таким образом, у вас есть массив, который вы сейчас используете выше, который содержит указатели на узлы, которые могут быть повторены, в какой бы цели вы его ни использовали. Затем у вас есть другой массив для экспресс-цели управления удалением, где каждый указатель происходит только один раз. Должно быть достаточно легко установить что-то вроде nodeCleanupArray[i] = pNewNode сразу после pNewNode = new Node(), после чего вы можете взорвать этот массив в линейном времени и delete каждого элемента. (Это означает, что вы не потрудились бы проверять элементы в массиве 1, вы бы полагались на nodeCleanupArray для очистки)

+0

Большое спасибо за быстрый и тщательный ответ. Однако как я могу управлять повторяющимися указателями в 'array1'? Я не могу использовать предварительно реализованные структуры динамических данных, такие как 'std :: vector' или любые другие STL-контейнеры для этого, потому что мне не разрешено делать это в моем проекте. – zawodny

+0

Отлично, это именно то, что я хотел сделать. Еще раз, извините за отсутствие ясности в моем объяснении проблемы, но мне не приходилось развлекаться с указателями на указатели на C++ ранее. Спасибо :) – zawodny

0

Попробуйте пометить и развернуть :) Вы пытаетесь реализовать управляемую среду.

Вот пример:

struct Node 
{ 
... 
    bool marked; 

    Node() : marked(false) 
    {} 
}; 

Теперь удаляет:

void do_delete(Node **data, size_t n) 
{ 
    size_t uniq = 0; 
    Node **temp = new Node*[n]; 

    for (size_t i = 0; i < n; i++) 
    { 
     if (data[i] && !data[i]->marked) 
     { 
      data[i]->marked = true; 
      temp[uniq++] = data[i]; 
     } 
    } 

    for (i = 0; i < uniq; ++i) 
    { 
     delete temp[i]; 
    } 

    delete[] temp; 
    delete[] data; 
} 
0

То, как я это сделал, имеет ссылочные счетчики и метод Node :: deref, который удалите сам узел, когда количество ссылок равно 0.При повторении через список узлов вызов node-> deref фактически не удаляет объект до последней ссылки узла в массиве.

1

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

std::vector< std::shared_ptr<Node> > 

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

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

0

Что такое правильный способ удалить array1 и все ее содержимое

Вы показать один распределение; new Node*[n]. Это распределение предоставляет программе ответственность за вызов delete [] whatever_the_return_value_was. Речь идет только об удалении этого выделения, а не об удалении «всего его содержимого». Если ваша программа выполняет другие распределения, то программа должна также организовать обработку этих обязанностей.

если есть возможность повторных указателей в массиве

Ну было бы неопределенным поведение, чтобы delete значения указателя, который не связан с каким-либо существующим распределением, так что вы должны избегать вычеркивания одно и то же значение указателя более одного раза. Это не проблема того, что существует один правильный путь, но проблема программирования, дизайна и т. Д.

Обычно C++ использует RAII для автоматического использования этого материала вместо того, чтобы пытаться делать то, что вы хотите вручную, потому что это вручную очень сложно. Один из способов использования RAII здесь состоял бы в том, чтобы иметь второй объект, который «владеет» Узлами. Тогда ваш array1 будет просто использовать указатели raw как указатели «не владеющие». Удаление всех узлов было бы сделано, если позволить собственному объекту узла выйти из сферы действия или иначе уничтожить.

{ 
    // object that handles the ownership of Node objects. 
    std::vector<std::unique_ptr<Node>> node_owner; 

    // your array1 object that may hold repeated pointer values. 
    std::vector<Node*> array1; 

    node_owner.emplace_back(new Node); // create new nodes 

    array1.push_back(node_owner.back().get()); // put nodes in the array 
    array1.push_back(node_owner.back().get()); // with possible duplicates 

    // array1 gets destroyed, but it's contents do not, so the repeated pointers don't matter 
    // node_owner gets destroyed and destroys all its Nodes. There are no duplicates to cause problems. 
} 

И разрушение происходит в линейном времени.

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