Деструктор - должен я использовать удалить или удалить []?

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

Теперь я хочу создать деструктор для этого контейнера. Как я должен освободить память, на которую указывает этот указатель? У меня нет способа знать априорно, является ли это массивом или единственным элементом.

Я - вид новых для C++, поэтому терпите меня. Я всегда использовал C, и Java является моим предпочтительным языком OO, но между желанием изучить C++ и требования к скорости моего проекта, я пошел с C++.

Это была бы лучшая идея изменить контейнер от шаблона до контейнера для абстрактного класса, который может реализовать его собственный деструктор?

7
задан Alex 3 February 2010 в 20:39
поделиться

11 ответов

Если вы не знаете, был ли он выделен с помощью new или new [] , то это небезопасно удалять его.

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

// by luck, this works on my preferred platform
// don't do this - just an example of why your code seems to work
int *ints = new int[20];
delete ints;

, а затем делаете это:

// crashes on my platform
std::string *strings = new std::string[10];
delete strings;
6
ответ дан 6 December 2019 в 06:24
поделиться

Краткий ответ:

Если вы используете [] с new, вы хотите использовать [] с delete.

//allocate some memory
myObject* m = new myObject[100];

//later on...destructor...
delete m; //wrong
delete[] m; //correct

Это были голые кости, еще одна вещь, на которую вы могли обратить внимание, - это boost . Также довольно сложно ответить, учитывая, что вы не уверены, массив это или один объект. Вы можете проверить это с помощью флага, сообщающего вашему приложению, следует ли использовать delete или delete [].

5
ответ дан 6 December 2019 в 06:24
поделиться

Поскольку указатель в C ++ не сообщает нам, как он был выделен, да, нет способа решить, какой метод освобождения использовать. Решение состоит в том, чтобы предоставить выбор пользователю, который, надеюсь, знает, как была выделена память. Взгляните на библиотеку Boost smart ptr , особенно на конструктор shared_ptr со вторым параметром, как отличный пример.

1
ответ дан 6 December 2019 в 06:24
поделиться

Причина использования альтернативной системы кодирования, отличной от HTML, заключается в безопасности

Уценка и другие такие системы кодирования в стиле вики обычно не поддерживают языки сценариев

HTML поддерживает языки сценариев многими способами (

Две основные проблемы безопасности:

  1. Преступники вредоносного ПО используют скрипты в пользовательском контенте для попытки вредоносных действий на компьютере считывателей контента путем создания скриптов для доступа к известным защитным отверстиям

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

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

Фильтрация HTML возможна, но также является сложной и рискованной

Другой важной причиной альтернативной системы кодирования является применение стиля. Обычный HTML имеет слишком много параметров. Ограничивая доступные параметры, пользователи могут использовать только определенные стили. Обычно это делает более чистый и читаемый контент (сравните SO с Ebay)

-121--2875902-

Если число предметов, возвращающих значение true , совпадает с числом всех предметов, то возвращает значение true . Просто как это:

Driveway.Cars(a => a.Red).Count() == Driveway.Cars.Count()

Родственное объяснение: Почему «abcd». StarstWith («») возвращает true?

-121-1118509-

(Перемещение моего комментария в ответ, по запросу.)

Ответ JonH правильный (об использовании разрушения массива только при использовании построения массива), так что, возможно, вы один для массивов, другой нет.

Другой ответ состоит в том, чтобы избежать массивов и вместо этого ожидать одного экземпляра, который может быть или не быть правильным набором, который очищается после себя, например, вектор < >.

изменить

Вопиюще украсть у Роджера Пейта, добавлю, что может потребоваться использование смарт-указателя, что равносильно коллекции из одного элемента.

2
ответ дан 6 December 2019 в 06:24
поделиться

Вы не должны удалять его вообще. Если ваш класс принимает уже инициализированный указатель, удалять его небезопасно. Он может даже не указывать на объект в куче; вызов либо delete , либо delete [] может иметь катастрофические последствия.

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

2
ответ дан 6 December 2019 в 06:24
поделиться

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

  • с использованием new
  • с использованием new []
  • с использованием malloc
  • с использованием пользовательской функции
  • и т. Д.

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

0
ответ дан 6 December 2019 в 06:24
поделиться

Если у вас есть класс, который принимает указатель, владельцем которого он станет, тогда контракт на использование класса должен включать одну из пары вещей. Либо:

  • интерфейс должен указывать, как объект, на который указывает указатель, был выделен, чтобы новый владелец мог знать, как безопасно освободить объект. У этого варианта есть то преимущество, что все упрощается (в любом случае на одном уровне), но он не гибкий - класс не может обрабатывать владение статическими объектами, а также динамически выделяемыми объектами.

или

  • интерфейс должен включать механизм, в котором политика освобождения может быть определена тем, что дает указатель на класс. Это может быть так же просто, как предоставление механизма для передачи функтора (или даже простого старого указателя на функцию), который будет вызываться для освобождения объекта (желательно в той же функции / конструкторе, которая передает сам указатель). Это, возможно, делает класс более сложным в использовании (но наличие политики по умолчанию для вызова delete указателя, например, может сделать его столь же простым в использовании, как вариант 1 для большинства применений). Теперь, если кто-то хочет дать классу указатель на статически выделенный объект, он может передать функтор без операции, чтобы ничего не произошло, когда класс хочет освободить его, или функтор на delete [] операция, если объект был выделен new [] и т. д.
2
ответ дан 6 December 2019 в 06:24
поделиться

Умный указатель, такой как boost shared_pointer, уже покрыл это, могли бы вы его использовать? линки

0
ответ дан 6 December 2019 в 06:24
поделиться

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

6
ответ дан 6 December 2019 в 06:24
поделиться

Как правило, вы должны придерживаться дизайна, в котором класс, вызывающий new , также должен вызывать delete

2
ответ дан 6 December 2019 в 06:24
поделиться
  • Используйте delete , если вы разместили с помощью new .
  • Используйте delete [] , если вы разместили new [] .

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

  • Всегда удаляйте то, что вы создали. Следствие: никогда не удаляйте то, что не создавали.
2
ответ дан 6 December 2019 в 06:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: