Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Теория (delete)

343
12 декабря 2006 года
lena_ki
282 / / 14.04.2005
Это одно и тоже или есть принципиальная разница:
TFileStream *stream = new TFileStream(OpenDialog1->FileName,fmOpenRead);
//использую
stream->~TFileStream();


TFileStream *stream = new TFileStream(OpenDialog1->FileName,fmOpenRead);
//использую
delete stream;

Это не мой код (первая часть). Я увидела его в другом приложении. Приложение работает. Возник вопрос: деструктор в этом случае освободит память?
Я всегда использую delete. Мне просто интересно с теоретической точки зрения. Первый код правильный?
18K
12 декабря 2006 года
dave
35 / / 12.12.2006
Цитата: lena_ki
Это одно и тоже или есть принципиальная разница:
TFileStream *stream = new TFileStream(OpenDialog1->FileName,fmOpenRead);
//использую
stream->~TFileStream();


TFileStream *stream = new TFileStream(OpenDialog1->FileName,fmOpenRead);
//использую
delete stream;

Это не мой код (первая часть). Я увидела его в другом приложении. Приложение работает. Возник вопрос: деструктор в этом случае освободит память?
Я всегда использую delete. Мне просто интересно с теоретической точки зрения. Первый код правильный?



конечно правильный.
но. применять явный вызов деструктора без надобности по меньшей мере странно.
применение этой вещи - placement new. то бишь размещение объекта в другой области памяти.

размещаем в куче память через new. а потом в этом размещении рожаем объект того типа, который нам нужно

цитирую:
Unlike ordinary new, placement new takes an additional argument: the memory address on which the object will be constructed. Since placement new doesn't really allocate storage, it's faster and safer than ordinary new. Of course, the programmer must guarantee that the pre-allocated storage is sufficiently large and that it meets the system's alignment requirements.

To meet these criteria, use ordinary new to allocate raw storage. Then use placement new to construct the desired object on the previously allocated storage.

char * raw_mem = new char [sizeof (Timer)];
...
C++ guarantees that the memory returned from new meets the strictest alignment requirements for every type of object. Therefore, you can use a dynamically allocated char array as the basis for constructing any other type of object

char * buff [sizeof (Timer)]; //bad idea
...
#include <new>
Timer * ptimer = new (raw_mem) Timer;

....

Objects allocated by placement new require an explicit destructor invocation once they aren't needed. Don't use delete or delete[] to destroy them as this would cause undefined behavior:
delete ptimer; // bad idea

The problem is that delete knows which object new allocated originally, namely a char array. It doesn't know that a different object was later constructed on that array. Therefore, it won't invoke Timer's destructor. Worse yet, because the original buffer was allocated using new[], you must use delete[] to release it. Here's how you invoke Timer's destructor:

ptimer->~Timer(); //explicit destructor invocation

240
12 декабря 2006 года
aks
2.5K / / 14.07.2006
В первом случае выполниться только сам деструктор. Освободит нужные ресурсы, а память выделенная под объект не освободится. (Если конечно что то типа delete this в нем не сделать)

Во втором случае деструктор тоже вызовется, а потом еще и удалиться память выделенная под объект.
309
12 декабря 2006 года
el scorpio
1.1K / / 19.09.2006
Dave
Что курил автор прицитированного английского текста ?????

Деструктор сам объект не удаляет, и уж тем более, не должен - иначе получим кучу глюков при повторном удалении.
Путать delete и delete[], а также free не рекомендуется - CodeGuard предупреждает.
Если требуется выделить память, используйте функцию malloc. Выделенную память требуется освобождать только через free.
18K
12 декабря 2006 года
dave
35 / / 12.12.2006
el scorpio
прошу обосновать предпосылки к куреву :))))
никто и не путает delete и delete[]
насчет функции malloc, боюсь мы начнем спорить о разности подходов.

Цитата:
Деструктор сам объект не удаляет, и уж тем более, не должен - иначе получим кучу глюков при повторном удалении.



предлагаю автору переписать/дополнить википедию.
из оттуда:

Дестру&#769;ктор &#8212; специальный метод класса, служащий для удаления объекта из памяти.

по Гради Бучу: Деструктор - Операция класса, которая освобождает состояние объекта и/или уничтожает сам объект.

по Страуструпу: Можно описать специальную функцию-член
для удаления объектов класса при его уничтожении. Такая
функция называется деструктором.

автор против всего мира ?

343
12 декабря 2006 года
lena_ki
282 / / 14.04.2005
Все разобралась. Вызов деструктора не освобождает память выделенную под объект в моем случае:
Код:
class A
   {
private:
   int* i;
public:
   A () : i (new int)
      {
 
      }
 
   ~A ()
      {
      delete i;
      }
   };
 
int main ()
   {
   A a;//все хорошо. в конструкторе выделели, в деструкторе освободили.
   A* aa = new A;//выделили в конструкторе и освободили в деструкторе память под int.              
   aa->~A ();    //НО память под A выделенную тут мы не освобождаем.
   }

Таким образом первый код это утечка памяти.
3
12 декабря 2006 года
Green
4.8K / / 20.01.2000
Вы запутались в двух понятиях: удаление объекта и освобождение памяти.
Деструктор удаляет объект, но не освобождает память.

Собственно, lena_ki уже сама разобралась... :)
18K
12 декабря 2006 года
dave
35 / / 12.12.2006
собственно Лена создала проблему, там где ее не было, и сама разобралась.

у Страуструпа глава 6.7.2 Указание размещения
и там явный вызов деструктора.

остальное, мне кажется, от лукавого
343
12 декабря 2006 года
lena_ki
282 / / 14.04.2005
Цитата: dave
собственно Лена создала проблему, там где ее не было



Я проблем не создовала. Просто задала вопрос по теории. :)

309
13 декабря 2006 года
el scorpio
1.1K / / 19.09.2006
Цитата: dave

по Страуструпу: Можно описать специальную функцию-член
для удаления объектов класса при его уничтожении. Такая
функция называется деструктором.


А что понимается под "объектом класса": объекты этого класса, или поля класса? Не знаю, что имел в виду сам Страуструп, но компиляторы C++ используют только второе трактование :D
Правда, при большом желании, можно создать функцию, которая будет удалять объект, освобождая занятую им память: operator delete (TMyClass *Object);

Если мыслить логически, то можно найти мегапричину, не позволяющую деструктору освобождать память, занятую объектом:
1. Объект может быть полем другого объекта - таким образом, занимаемая им память будет принадлежать объекту-владельцу, со всеми вытекающими последствиями по части выделения/освобождения памяти.
2. Объект может быть локальным - расположенным в стеке программы - а эта область памяти вообще не выделяется и не освобождается при работе приложения.
Как видно, освобождение памяти находится вне компетенции деструктора. Для этого есть два оператора (delete и delete[]) и две функции (free и realloc (Адрес, 0)), которые вызываются только для самостоятельных объектов, расположенных в "куче".

P.S. Насчёт "курения":

 
Код:
char * raw_mem = new char [sizeof (Timer)];
//....
Timer * ptimer = new (raw_mem) Timer;

На трезвую голову такое придумать сложно :D . Адекватные люди, если не любят new :confused: , пишут malloc и не балуются "промежуточными" типами.
3
13 декабря 2006 года
Green
4.8K / / 20.01.2000
Но ведь можно и так:
 
Код:
Timer* raw_mem = new char [sizeof (Timer)];
//....
Timer* ptimer = new (raw_mem) Timer;

или даже так:
 
Код:
Timer* raw_mem = operator new( sizeof (Timer) );
//....
Timer* ptimer = new (raw_mem) Timer;
309
14 декабря 2006 года
el scorpio
1.1K / / 19.09.2006
Но зачем :eek:?
Тем более, что в первом примере потом будет сложно удалять
 
Код:
pTimer->~Timer()
delete [] (char*) pTimer;

А чем второй пример лучше простого new Timer(), записанного в одну строку ;) ?
Конечно, ручной вызов деструкторов и конструкторов тоже имеет своё применение - но такие случаи редко бывают.


P.S. Ох, запутаем сейчас начинающих.... А им лучше всего запомнить "главное правило" - не усложнять :D
3
14 декабря 2006 года
Green
4.8K / / 20.01.2000
А за тем, что ты упустил многоточие, которое сам же и поставил когда-то между двух строк кода.
Объясняю. После выделения памяти под объект и перед конструированием самого объекта может пройти некоторое время, выполниться другие необходимые операции. Аналогично после удаления объекта и перед освобождением памяти.

Например, контейнер std::vector. Как известно память в нем выделяется с запасом, и объекты конструируются уже в выделенной памяти.

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

Ещё пример: структуры переменной длины:
 
Код:
struct String
{
   int size;
   char content[1];
};
309
14 декабря 2006 года
el scorpio
1.1K / / 19.09.2006
Ладно, понял. А вот почему тогда именно new[] / delete[]?
В своих программах мне порою тоже приходилось реализовывать механизмы выделения/освобождения памяти. Но я использовал более традиционные функции malloc, realloc и free.
3
14 декабря 2006 года
Green
4.8K / / 20.01.2000
Вопрос интересный.
Точно сказать не могу, надо искать ответ.
Но могу предположить:
1) для единой стилистики в программах на С++, malloc - это все же C, а реализация new может быть и не завязана на malloc;
2) неудачный malloc возвращает 0, а вот неудачный new в зависимости от настроек компиляции может как вернуть 0, сгенерировать исключение или вызвать специальную callback-функцию new_handler, которая устанавливается с помощью set_new_handler.
IMHO, отличное предположение.

Знаете кого-то, кто может ответить? Поделитесь с ним ссылкой.

Ваш ответ

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог