Удалить переменную из памяти
В C++ можно использовать различные типы объектов, которые различаются по использованию памяти. Так, глобальные объекты создаются при запуске программы и освобождаются при ее завершении. Локальные автоматические объекты создаются в блоке кода и удаляются, когда этот блок кода завершает работу. Локальные статические объекты создаются перед их первым использованием и освобождаются при завершении программы.
Глобальные, а также статические локальные объекты помещаются в статической памяти, а локальные автоматические объекты размещаются в стеке. Объекты в статической памяти и стеке создаются и удаляются компилятором. Статическая память очищается при завершении программы, а объекты из стека существуют, пока выполняется блок, в котором они определены.
В дополнение к этим типам в C++ можно создавать динамические объекты . Продолжительность их жизни не зависит от того, где они созданы. Динамические объекты существуют, пока не будут удалены явным образом. Динамические объекты размещаются в динамической памяти (free store).
Для управления динамическими объектами применяются операторы new и delete .
Оператор new выделяет место в динамической памяти для объекта и возвращает указатель на этот объект.
Оператор delete получает указатель на динамический объект и удаляет его из памяти.
Выделение памяти
Создание динамического объекта:
Оператор new создает новый объект типа int в динамической памяти и возвращает указатель на него. Значение такого объекта неопределено.
Также можно инициализировать объект при создании:
Освобождение памяти
Динамические объекты будут существовать пока не будут явным образом удалены. И после завершения использования динамических объектов следует освободить их память с помощью оператора delete :
Особенно это надо учитывать, если динамический объект создается в одной части кода, а используется в другой. Например:
В функции usePtr получаем из функции createPtr указатель на динамический объект. Однако после выполнения функции usePtr этот объект автоматически не удаляется из памяти (как это происходит в случае с локальными автоматическими объектами). Поэтому его надо явным образом удалить, использовав оператор delete.
Использование объекта по указателю после его удаления или повторное применение оператора delete к указателю могут привести к непредсказуемым результатам:
Поэтому следует удалять объект только один раз.
Также нередко имеет место ситуация, когда на один и тот же динамический объект указывают сразу несколько указателей. Если оператор delete применен к одному из указателей, то память объекта освобождается, и по второму указателю этот объект мы использовать уже не сможем. Если же после этого ко второму указателю применить оператор delete, то динамическая память может быть нарушена.
В то же время недопустимость указателей после применения к ним оператора delete не означает, что эти указатели мы в принципе не сможем использовать. Мы сможем их использовать, если присвоим им адрес другого объекта:
Здесь после удаления объекта, на который указывает p1, этому указателю передается адрес другого объекта в динамической памяти. Соответственно мы также можем использовать указатель p1. В то же время адрес в указателе p2 по прежнему будет недействительным.
Аргумент приведения выражения должен быть указателем на блок памяти, ранее выделенный для объекта, созданного с помощью нового оператора. Оператор delete имеет результат типа void и, следовательно, не возвращает значение. Пример:
Использование delete указателя на объект, не выделенный с непредсказуемыми new результатами. Однако можно использовать delete указатель со значением 0. Эта подготовка означает, что при new возвращении 0 при сбое удаление результата неудачной new операции безвредно. Дополнительные сведения см . в разделе "Новые и удаленные операторы".
Операторы new и delete операторы также можно использовать для встроенных типов, включая массивы. Если pointer ссылается на массив, поместите пустые скобки ( [] ) перед pointer :
delete Использование оператора для объекта освобождает память. Программа, которая разыменовывает указатель после удаления объекта, может создать непрогнозируемый результат или вызвать сбой.
Когда delete используется для освобождения памяти для объекта класса C++, деструктор объекта вызывается до освобождения памяти объекта (если объект имеет деструктор).
Если операнд delete оператору является изменяемым l-значением, его значение не определено после удаления объекта.
Если указан параметр компилятора /sdl (включение дополнительных проверок безопасности), операнд delete оператору присваивается недопустимое значение после удаления объекта.
Использование оператора delete
Существует два синтаксических варианта для оператора delete: один для отдельных объектов, а другой для массивов объектов. В следующем фрагменте кода показано, как они отличаются:
В следующих двух случаях возникают неопределенные результаты: использование формы массива удаления ( delete [] ) для объекта и использование неаррейской формы удаления в массиве.
Пример
Примеры использования delete см. в разделе "Новый оператор".
Принцип работы delete
Оператор delete вызывает удаление оператора функции.
Для объектов, не относится к типу класса (классу, структуре или объединению), вызывается глобальный оператор удаления. Для объектов типа класса имя функции освобождения разрешается в глобальной области, если выражение delete начинается с оператора разрешения унарной области ( :: ). В противном случае перед освобождением памяти оператор удаления вызывает деструктор объекта (если указатель не имеет значения null). Оператор удаления можно определять отдельно для каждого класса; если для некоторого класса такое определение отсутствует, вызывается глобальный оператор удаления. Если выражение удаления используется для освобождения объекта класса, статический тип которого имеет виртуальный деструктор, функция освобождение разрешается через виртуальный деструктор динамического типа объекта.
C++ поддерживает динамическое выделение и освобождение объектов с помощью new операторов и delete операторов. Эти операторы выделяют память для объектов из пула, называемого свободным хранилищем. Оператор new вызывает специальную функцию operator new , а delete оператор вызывает специальную функцию operator delete .
Функция new в стандартной библиотеке C++ поддерживает поведение, указанное в стандарте C++, которое вызывает std::bad_alloc исключение при сбое выделения памяти. Если вы по-прежнему хотите использовать неисключающую версию new , свяжите программу с nothrownew.obj . Однако при связывании со nothrownew.obj стандартной библиотекой C++ значение по умолчанию operator new больше не работает.
Список файлов библиотеки в библиотеке среды выполнения C и стандартной библиотеке C++ см. в разделе "Функции библиотеки CRT".
Оператор new
Компилятор преобразует оператор, например этот, в вызов функции operator new :
Если запрос равен нулю байтов хранилища, operator new возвращает указатель на отдельный объект. То есть повторяющиеся вызовы для operator new возврата разных указателей. Если для запроса на выделение недостаточно памяти, operator new возникает std::bad_alloc исключение. Или возвращается nullptr , если вы связали в поддержке, отличной от создания operator new .
Вы можете написать подпрограмму, которая пытается освободить память и повторить выделение. Для получения дополнительной информации см. _set_new_handler . Дополнительные сведения о схеме восстановления см. в разделе "Обработка нехватки памяти ".
Две области для operator new функций описаны в следующей таблице.
Область для operator new функций
Оператор | Область |
---|---|
::operator new | Глобальный |
имя класса ::operator new | Класс |
Первый аргумент operator new должен иметь тип size_t , определенный в , и возвращаемый тип всегда void* .
Глобальная operator new функция вызывается, когда new оператор используется для выделения объектов встроенных типов, объектов типа класса, не содержащих определяемых operator new пользователем функций, и массивов любого типа. new Если оператор используется для выделения объектов определенного типа operator new класса, вызывается этот класс operator new .
Функция, определенная operator new для класса, является статической функцией-членом (которая не может быть виртуальной), которая скрывает глобальную operator new функцию для объектов этого типа класса. Рассмотрим случай, когда new используется для выделения и задания памяти заданному значению:
Аргумент, указанный в скобках, new передается Blanks::operator new в качестве аргумента chInit . Однако глобальная operator new функция скрыта, что приводит к возникновению ошибки, например следующего:
Компилятор поддерживает массив new элементов и delete операторы в объявлении класса. Пример:
Обработка нехватки памяти
Тестирование на выделение памяти сбоем можно выполнить, как показано ниже.
Существует еще один способ обработки неудачных запросов на выделение памяти. Напишите пользовательскую подпрограмму восстановления для обработки такого сбоя, а затем зарегистрируйте функцию, вызвав _set_new_handler функцию времени выполнения.
Оператор delete
Память, которая динамически выделяется с помощью new оператора, можно освободить с помощью delete оператора. Оператор удаления вызывает функцию operator delete , которая освобождает память обратно в доступный пул. delete Использование оператора также приводит к вызову деструктора класса (если таковой существует).
Существуют глобальные и классовые operator delete функции. Для заданного класса можно определить только одну operator delete функцию. Если она определена, она скрывает глобальную operator delete функцию. Глобальная operator delete функция всегда вызывается для массивов любого типа.
Глобальная operator delete функция. Для глобальных operator delete и членных operator delete функций существуют две формы:
Для данного класса может присутствовать только одна из предыдущих двух форм. Первая форма принимает один аргумент типа void * , который содержит указатель на объект для освобождения. Вторая форма, освобождение размера, принимает два аргумента: первая — указатель на блок памяти для освобождения, а второй — количество байтов для освобождения. Тип возвращаемого значения обеих форм ( void operator delete не может возвращать значение).
Цель второй формы — ускорить поиск правильной категории размера удаляемого объекта. Эта информация часто не хранится рядом с самим выделением и, скорее всего, не качается. Вторая форма полезна, если operator delete функция из базового класса используется для удаления объекта производного класса.
Функция operator delete является статической, поэтому она не может быть виртуальной. Функция operator delete подчиняется управлению доступом, как описано в разделе "Член-контроль доступа".
В следующем примере показаны определяемые operator new пользователем функции и operator delete функции, предназначенные для записи выделения и освобождения памяти:
Приведенный выше код можно использовать для обнаружения утечки памяти, то есть памяти, выделенной в свободном хранилище, но никогда не освобождаемой. Для обнаружения утечек глобальные new и delete операторы переопределяются для подсчета выделения и освобождения памяти.
Компилятор поддерживает массив new элементов и delete операторы в объявлении класса. Пример:
public static UserInterface user;
После закрытия в данном случае Android приложения (onDestroy метод) ссылка сохранилась в памяти как собственно и объект, из за этого в методе onCreate не сработало условие
Как удалить объект из памяти?
На данный момент на уме только поставить (user = null) в onDestroy;
Никак. Эта работа мусоросборщика. Чтобы дать ему понять что объект можно стереть из памяти нужно удалить все ссылки на него. Т.е.:
@oxInSox немного слукавил. Дело в том, что обнулив ссылочную целостность не будет гарантировать уничтожение объекта. После этого желательно и заставить мусоросборник работать
System.gc();
Особенно это важно для объектов наследников трэдов и раннебол.
@svd71 вы врете, System.gc не заставляет никого ничего делать. Вызвав этот метод вы лишь намекнете виртуальной машине, что хотите запустить мусоросборщик. Запускать его или нет машина решит уже сама.
Какова вероятность запуска гербачколлектора выше: без обращения к данному методу или с обращением?
ПС: И учитесь подбирать выражения. Иначем мне придется призвать модераторов для получения ваших извинений.
@svd71 Причем тут вероятность? Вы пообещали всему интернету что вызов System.gc заставить мусоросборщик работать. Это не так, почитайте документацию.
PS Вы не политик случайно? Очень похоже: сначала обещать, а потом пугать полицией. Призывайте модераторов, надеюсь они удалят ваш ответ.
Тоже задался похожим вопросом. Ранее писал на AS(Flash) там с обработчиками туго, приходиться следить самому. Сейчас в JAVA столкнулся с похожей задачей.
Пример:
Есть некий список чекбоксов, подписываюсь на изменение состояния каждого из них. Сам же список формирует модель из выбранного пользователем файла.
Вопрос:
Важно ли отписываться от каждого чекбокса в случае обновления списка или достаточно просто удалить сам чекбокс?
Просто, список полей не малый и желание оптимизировать постоянно отвлекает. Заранее спасибо!
Пишу простенький класс на C++.
В классе есть такой конструктор:
И такой деструктор:
Однако по завершению программы вылетает исключение с таким содержанием:
HEAP CORRUPTION DETECTED
Еще есть такой кусок кода, валится на выделенной строке:
Самое забавное, что такая проблема только тогда, когда я собираю под Debug. Под Release программа отрабатывает корректно до конца.
Что я делаю не так?
Ошибка вылетает только при компиляции в Debug, потому что в этом режиме, скорее всего, в код включаются проверки целостности кучи. Просто в release целостность кучи не проверяется, но это не значит, что ошибки нет.
Ошибка тут:
for (int i = 0; i Вместо deg нужно использовать maxdeg, имхо.
Кроме того вы не проверяете значение deg и maxdeg до выделения памяти. Что если они содержат значения
Возможно, есть и другие места с присваиванием массиву data и переменной deg. Нужно искать выход за границу массива при присваивании элементам массива из-за чего повреждается куча.
Так же настораживает new int[deg +1] и операторы >= и
PS: в качестве небольшой оптимизации: для обнуления массива можно использовать функцию memset, для копирования массивов - memcpy.
res2001 , добавлю тебе в ответ мои пять копеек.
В отладочной сборке не "скорее всего", а точно включается код проверки целостности кучи.
Если иметь окружение MS Visual Studio, то при отладке даже сама куча работает в режиме отладки. Это уже означает, что при выделении памяти происходит маркировка ее границ - установка т.н. забора, а в заголовке выделенного участка пишутся дополнительные данные.
Сам забор из себя представляет 4 одинаковых байта перед выделенным участком (и после его заголовка) и 4 таких же одинаковых байта сразу после выделенного участка.
При освобождении выделенной памяти делается гора проверок, среди которых - проверка целостности забора. Это - одна из основных причин падения производительности при запуске в отладке в MS VC++.
Когда речь идет о выделении памяти, т.е. создании динамических массивов или просто указателей на блоки памяти. То выглядит это следующим образом:
int size = .
int *array = new int[size];
int* p = NULL;
p = new int;
замень, тут всегда идет указатель на выделенный блок памяти.
Соотвественно и деструкторе для массивов идет
delete [] array;
или delete p;
В твоем примере
все вроде бы верно, при условии, что дата это указатель, который декларирован где-то в классе заранее.
Точный ответ на вопрос дать не могу поскольку код представлен не полностью. Вероятнее всего data в классе объявлена не верно, она должна быть указателем на массив и никак иначе, pointersaver в коде ниже тоже должен быть указателем на массив, хотя бы преобразовываться к этому типу (с помощью static_cast) в месте вызова delete.
Вообще при использовании C++ настоятельно рекомендуется использовать ссылки, умные указатели unique_ptr, и готовые конструкции для типов, подойдёт array.
Если же целью ставится разобраться в "сырых" указателях и работе с ними, то стоило бы вместо цикла for (int i = deg; i >= 0; i--) data[i] = 0; использовать memset.
Однако повторюсь, в общем случае гораздо лучше написать высокоуровневый код использую стандартную библиотеку и не лазая в дебри прямого доступа к памяти и других низкоуровневых конструкций.
P.S. в Release код сильно изменяется компилятором в процессе оптимизации и из-за большего количества "знаний о коде" компилятор может сгенерировать его гораздо чище чем он был написан, а в Debug оптимизации не применяются и поэтому код будет работать так как написан.
Читайте также: