| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Объясните конструкцию ptr->~ClassName() |
| Автор: borisbn 24.3.2011, 10:57 | ||||
В различном коде не часто, но встречается конструкция вида
Можете объяснить назначение такого вызова ? Правильно ли я понимаю, что delete делает примерно следующее:
а ptr->~ClassName(); только вызывает деструктор, а память не освобождает ? Если правильно, то подскажите, пожалуйста, в каких случаях это используется. Спасибо. |
| Автор: azesmcar 24.3.2011, 11:04 | ||||
| borisbn В C++ есть возможность создать объект в заранее выделенной области памяти.
По сути это явный вызов конструктора. Аналогично для удаление этого объекта необходимо вызвать деструктор и освободить память.
|
| Автор: Modul 24.3.2011, 11:37 | ||||||
При этом происходит не удаление указателя, а освобождение области памяти по адресу, записанному в нем. С самим указателем ничего не происходит и ему можно присвоить другой адрес. Рекомендуется указателю присваивать нулевое значение. Да. Поэтому оператор delete предпочтительнее (освобождает память и удаляет объект). А что у нас обычно в деструкторе ? Что-то удаляем (объекты). Если при создании объекта имеется динамическое распределение памяти, то выделение памяти делают в конструкторе, ее освобождение - в деструкторе. Т.е. для освобождения памяти и удаления объектов класса. В конструкторе:
В деструкторе:
А наш объект (типа ClassName) при этом не удаляем, только чистим память. |
| Автор: azesmcar 24.3.2011, 12:01 | ||
Например тебе необходимо создать огромное количество мелких объектов, и чтобы не вызывать проблем с фрагментацией памяти выделяешь сразу большой кусок, в котором в дальнейшем создаешь свои объекты. Или например твоей программе требуется много памяти, и чтобы в дальнейшем избежать исключения с bad_alloc ты при запуске выделяешь столько, сколько необходимо (если есть) и работаешь уже с выделенной памятью. Примеров много, другое дело, что это не часто требуется. |
| Автор: Modul 24.3.2011, 12:10 | ||
Конечно знаешь ! Просто сразу не догадался, потому спросил.
А потом еще надо отдельную функцию сделать, чтобы их снова в динамике создать. Подумалось. Итого у нас для раздумий 2 варианта. |
| Автор: borisbn 24.3.2011, 12:12 |
| azesmcar, т.е. (если я правильно понял) это используется только когда сам делашь менеджер памяти (ну или, скажем, его основной функционал). OK, спасибо. закрываю. |
| Автор: azesmcar 24.3.2011, 12:14 | ||||
Не только, скорее в основном. Явный вызов деструктора нужен тогда, когда ему предшествовал явный вызов конструктора. Еще один пример использования можешь посмотреть у Александреску - http://books.google.am/books?id=aJ1av7UFBPwC&pg=PA137&lpg=PA137&dq=phoenix+singleton+Alexandrescu&source=bl&ots=YRaD3sWc4Y&sig=j32rbRbdx2GRMrA8AxAHJWYWgpI&hl=en&ei=UguLTZysJpGwhQfJiImrDg&sa=X&oi=book_result&ct=result&resnum=1&ved=0CBIQ6AEwAA#v=onepage&q&f=false. В общем-то это возможность языке, а где и как ее применять личное дело каждого.
не совсем понял о чем речь. |
| Автор: Modul 24.3.2011, 12:19 |
Если мы дальше хотим работать с объектом, снова надо эти мелкие объекты (может массивы) создать после их удаления в деструкторе в отдельной функции. |
| Автор: bsa 24.3.2011, 12:29 | ||
Посмотрите реализацию std::vector. Там это используется - reserve() выделяет блок памяти, resize() создает объекты в уже выделенной области. |
| Автор: Modul 24.3.2011, 12:38 | ||
bsa, я про такой вариант:
Думаю, может меня остальные не поняли. При создании объекта имеется динамическое распределение памяти (мелкие объекты), выделение памяти сделали в конструкторе, ее освобождение - в деструкторе. Вызвали явно деструктор, мелкие объекты удалили. При дальнейшей работе с нашим объектом (его не удалили) эти мелкие динамические объекты снова создаем через отдельный метод. |
| Автор: bsa 24.3.2011, 13:49 |
| Modul, я опять не понял, о чем ты говоришь. Если об освобождении ресурсов деструктором, которые выделил конструктор, то это и ежу понятно. Причем не важно, выделялись ли они на самом деле или нет. Если сконструировал объект, то изволь его затем деконструировать. И не важно, int это, или мега сложный класс управления стержнями ядерного реактора. |
| Автор: borisbn 24.3.2011, 14:18 |
| bsa, хммм. Действительно, каждый день пользую, а не подумал про вектор. Там, пожалуй, по-другому и не сделаешь. |
| Автор: Modul 24.3.2011, 14:24 | ||
1) delete myObject; С этим всем ясно ! 2) По сабжу собственно: 1. создали объект ClassName *myObject = new ClassName; В конструкторе у нас были мелкие динамические объекты, типа:
2. вызвали явно деструктор myObject->~ClassName(); и удалили все наши мелкие динамические объекты. delete pPointer; Объект myObject у нас существует - занимает память, а наши мелкие динамические объекты удалены. 3. Для новой работы с объектом myObject требуется создать снова наши мелкие динамические объекты, созданные в конструкторе (например, pPointer). Для этого я предлагал сделать отдельную функцию. И шото меня не поняла общественнось. |
| Автор: bsa 24.3.2011, 16:02 | ||
Да потому что ты какую-то ерунду сморозил. Назови хоть один пример, когда требуется делать так, как ты рекомендуешь? Непосредственный вызов деструктора используется ТОГДА И ТОЛЬКО ТОГДА, когда использовался размещающий new. Так как этот оператор просто вызывает конструктор, передавая ему в качестве указателя this адрес заданной тобой области памяти. Используется это для создания так называемых пулов - собственных "куч". Пример:
|
| Автор: Modul 24.3.2011, 16:49 | ||||||
| Привожу мою ерунду: My.h
My.cpp
main.cpp
|
| Автор: bsa 24.3.2011, 16:55 |
| Я и без примеров прекрасно понял о чем речь. Я не понял, ЗАЧЕМ? Назови хоть одну причину, по которой нужно городить такой неочевидный и опасный код? Какова вероятность, что человек не забудет вызывать деструктор перед вызовом create()? И если тебе нужно проинициализировать заново объект, то кто мешает использовать operator= или, если совсем критично по скорости, конструкцию My().swap(myObject)? |
| Автор: Modul 24.3.2011, 17:06 | ||
Это по сабжу, что так можно.
Например, удаление (очистка) массы этих переменных. Ну, дорогой bsa, Вы же сами прекрасный программист. И степень опасности он же и определяет. Все в его ровных (или кривых) руках. p.s. Так никогда сам не делал, это к сабжу все. |
| Автор: mes 24.3.2011, 20:00 |
хороший пример, как ни в коем случае нельзя делать... |
| Автор: Modul 24.3.2011, 20:46 |
| "... а кто знает, тот не говорит" - народная китайская поговорка. Расскажите почему, просим... |
| Автор: mes 24.3.2011, 21:22 | ||
главный ответ тут :
еще нужно вспомнить о правиле хорошего тона, о соблюдении симметрии создания и удаления.. ну и как результат в вашем примере будет либо двойной вызов деструктора, либо память не будет освобождена.. |
| Автор: Modul 24.3.2011, 21:42 |
Т.е. мы один раз удалили при удалении в деструкторе, а потом при удалении нашего объекта myObject еще раз. |
| Автор: mes 24.3.2011, 21:55 | ||
один раз Вы вызвали деструктор вручную, а второй раз вызовется при выходе за границы пользования (для стекового и статического объектов) или при вызове delete (для объекта кучи) обратите внимание на пример bsa.. память в которой размещается объект имеет тип char -т.е. пустой буфер, при удалении которого никаких деструкторов не надо.. |
| Автор: borisbn 24.3.2011, 21:55 | ||||
как ТС вставлю своё слово... вообще-то сабж был не "можно ли это" а
Добавлено через 1 минуту и 58 секунд вообще-то, я уже всё понял, поэтому отвечать на эти три вопроса не нужно |
| Автор: Modul 24.3.2011, 22:06 |
| Спасибо, borisbn, за Вашу тему ! Поэтому, она позволили не только Вам найти ответ на Ваш вопрос, но и мне и другим людям в сообществе. А плохо это или хорошо, это решать программисту. Спасибо большое всем ! |
| Автор: bsa 24.3.2011, 23:20 |
К сожалению. С++ позволяет слишком многое, чем "пользуются" недостаточно опытные программисты, не знающие, чем это черевато. |
| Автор: mes 24.3.2011, 23:25 |
хотя и написана куча литературы, о том как сделать приятно и себе и людям.. |
| Автор: Modul 24.3.2011, 23:38 |
| Философские мысли: Как ужасно спится манагеру, который продает ужасную программу г....но клиенту с г...кодом. который приходит в 14-15 часов и говорит, ну что...клиент убегает, нас увольняют, закрывают... Потом приходит и говорит после 5 мин. базара, опа, А как мы вчера ДУНУЛИ !!! Надо спросить Бориса. |
| Автор: borisbn 24.3.2011, 23:40 |
верю |
| Автор: alexvs11 24.3.2011, 23:47 |
| первое что приходит в голову - вызов деструктора, чтобы по этому же адресу вызвать явно конструктор так можно заново проинициализировать объект, при этом все внешние ссылки на этот объект останутся валидными |
| Автор: bsa 25.3.2011, 13:22 | ||||
Более безопасный способ:
|
| Автор: alexvs11 25.3.2011, 22:06 |
| bsa, ну можно и operator=, но так в сам класс не требуется вносить никаких изменений, те удобно для несвоих классов хотя опасно-опасно |
| Автор: bsa 25.3.2011, 22:53 | ||
operator=() в общем случае работает дольше, так как реализуется:
|