| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > локальный сборщик мусора |
| Автор: Леопольд 29.6.2009, 20:12 | ||
| Локальный сборщик мусора. Подчищает "хвосты" во время саморазрушения. Безопасен при исключениях. Покритикуйте пожалуйста, только без грубостей, я нежный... 30.06.2009. Переписал. Интерфейс немного изменился.
|
| Автор: andrew_121 29.6.2009, 20:13 |
тьфу! |
| Автор: Леопольд 29.6.2009, 20:18 | ||
Пример использования:
Добавлено @ 20:18 очень конструктивно... |
| Автор: andrew_121 29.6.2009, 20:30 |
Прошу прощения. Это не о коде! Это реакция о том, что я процитировал. Опять же, прошу прощения за оффтоп. Мое почтение! |
| Автор: Леопольд 29.6.2009, 20:32 | ||
Блаженно улыбаюсь |
| Автор: Леопольд 29.6.2009, 20:49 | ||
Если не создавать, то как разрушать автоматически, например, при порождении исключения? |
| Автор: zim22 29.6.2009, 20:55 | ||||||||
никак. деструктор вызывается автоматически. хотя можно и явно его вызвать вы хотели расширить auto_ptr, чтобы он мог корректно работать с массивами? имхо, лучше отдельный класс написать тогда:
http://www.research.att.com/~bs/bs_faq2.html#auto_ptr Страуструп объясняет, почему не нужен auto_array
*** я попробовал с помощью функций реализовать, но не получилось т.к. я объекты храню как указатели на void*, а при удалении необходимо void* преобразовать к типу...
|
| Автор: ЗапаснойЛеопольд 29.6.2009, 22:01 | ||||
Неа, мне было интересно сделать примитивный сборщик мусора для объектов произвольного типа и размерности, который, при этом правильно их уничтожает. auto_array не предназначен для этого. Моя штуковина намного гибче пример:
По какой-то причине я не могу постить под моим основным аккаунтом на форуме до завтрашнего вечера. Я что-то нарушил? |
| Автор: ЗапаснойЛеопольд 29.6.2009, 22:36 | ||||
В шаблоне передается шаблон Так как это локальный сборщик мусора. То проще всего хранить его как объект. Можно, например, хранить как объект класса, в приватной части, для автоуборки при разрушении класса. Можно усовершенстовть так, чтобы контейнер тоже задавался в виде шаблонного параметра. У меня не получилось сделать с аргументом шаблона по умолчанию, STL контейнеры имеют свои шаблонные параметры по умолчанию, а я не помню как это побороть.
|
| Автор: andrew_121 29.6.2009, 22:51 |
| ЗапаснойЛеопольд, Классный ник! |
| Автор: Lazin 29.6.2009, 22:57 | ||||
можно передавать в качестве шаблонного параметра структуру, внутри которой будет шаблон
только я не очень понимаю, чем этот класс лучше обычного scoped_ptr? |
| Автор: ЗапаснойЛеопольд 29.6.2009, 22:58 | ||||||||||
Сам придумал!!! Добавлено @ 23:04
Ничем. Даже хуже из-за необходимости держать всё в одном контейнере. Причём всегда с виртуальным деструктором. Просто интересная головоломка... Хотя, если scoped_ptr не позволяет задавать кустарную очистку памяти (в чём я сомневаюсь)... но мне сейчас поздно лезть в boost.org , спать пора...
Но ведь красиво! Добавлено @ 23:09
Не понял. Чем это удобнее чем man.push<garbage::del_array>(new int[10])? |
| Автор: DrHex 30.6.2009, 00:53 |
| Зачем вообще collector? Деструктор не годится?(collector только добовляет накладные ресурсы) |
| Автор: Lazin 30.6.2009, 05:51 | ||||
ты же попросил пример вообще, вариант, который я предложил применяется в boost.mpl, лучше он тем, что обычные шаблонные параметры проще использовать, расширяемость лучше итд... можно еще использовать идиому traits
в этом случае тебе не нужно будет явно указывать garbage::del_array для каждого вызова, вместо этого ты можешь специализировать класс del_traits, для своего типа, и он будет использоваться в методе push |
| Автор: Леопольд 30.6.2009, 22:49 | ||||||
Я имел ввиду пример использования. Т.е., допустим, есть жалоба от потенциального пользователя что использование моей штуковины неудобное. Я не знаю как можно придумать удобнее, сохранив при этом обобщённость: ============================================================================================ garbage::collector cleaner; ... AnyType* ptr = cleaner.push<garbage::del_single>(new AnyType); ... AnotherType* array = cleaner.push<garbage::del_array>(new AnotherType[size]); ... SpecialType* something = cleaner.push<special_clean_array>(special_alloc(SpecialType)); ============================================================================================ Если есть идеи, как можно упростить это или сделать более наглядным, буду благодарен... Добавлено @ 22:55
traits не подходит по той причине что я могу захотеть удалять указатель на один и тот же тип разными способами. Т.е. int* ptr = cleaner.push<garbage::del_single>(new int); int* array = cleaner.push<garbage::del_array>(new int[size]); Добавлено @ 22:59 Я переписал утилитку, gcc не хотел собирать (новая версия в первом посте). Получилось даже лучше. Я так же изменил способ хранения указателей на объекты на максимально лёгкий, какой смог придумать. Теперь сборщик уступает scoped_array (для целей локальной автоуборки) только виртуальными вызовами деструкторов. Это плата за универсальность. Хотя, было бы неплохо от этого избавиться. Но как это сделать не меняя способа использования, я не знаю. |
| Автор: Леопольд 30.6.2009, 23:11 | ||
Можно поподробнее? Ничего же не понятно... |
| Автор: mes 1.7.2009, 01:32 |
| мне вот прежде всего непонятно, зачем нужен такой контейнер, да еще и локальный. не проще ли было бы просто пользовать обертку для каждого объекта отдельно ? |
| Автор: Lazin 1.7.2009, 08:42 | ||||||||
так у тебя там и нет особой обобщенности, все довольно жестко задается на этапе компиляции... например, у меня есть класс - пулл объектов, в котором я выделяю память, допустим, для удаления объекта, нужно вызывать метод free пулла, и передать в него указатель на объект, который нужно удалить.. допустим, в программе может быть несколько таких пуллов в этом случае, твой deleter должен получать ссылку или указатель на пул объектов, из которого нужно этот объект потом удалить, с твоим кодом это сделать не получится, следовательно он не гибок
во вторых, у тебя объекты могут удалятся в произвольном порядке, это зависит от того, как их добавлять, если порядок удаления важен, то это может вызвать сложности
это уже извращение, для массивов есть vector к тому-же, если у тебя объект одного типа удаляется несколькими разными способами, то это уже ошибка, лучше всего делать так, что-бы можно было на этапе компиляции однозначно определить как удалять объект, к примеру, если у тебя есть класс Foo, и он может быть создан в куче или с помощью специализированного менеджера памяти(и удаляться с помощью него), то во втором случае, лучше использовать какой-нибудь смарт поинтер вместо обычного указателя, что-бы можно было определить на этапе компиляции, как удалять объект. я сделал-бы это так:
ничего не напоминает? |
| Автор: ЗапаснойЛеопольд 1.7.2009, 09:11 | ||||
каких именно несвязанных операций и почему они несвязанные? объекты удаляются в порядке обратном созданию. |
| Автор: Леопольд 1.7.2009, 09:16 | ||||||||||
Вот ещё одно извращение
Добавлено через 1 минуту и 56 секунд
Напиши пожалуйста интерфейс пула, а я попытаюсь им воспользоваться... |
| Автор: Lazin 1.7.2009, 09:22 | ||||||||||
| они удаляются в порядке, обратном вызовам ф-ии push если у меня есть объекты А и Б и я хочу, что-бы они были удалены после выхода из scope, то зачем-то создается список, в котором лежат указатели на А и Б(это как минимум два выделения памяти в куче), хотя достаточно пары стековых объектов? почему удаление объектов А и Б должно для меня выглядеть как одна операция, хотя это 2 операции не связанные между собой? Добавлено через 5 минут и 10 секунд
создание
удаление
|
| Автор: Леопольд 1.7.2009, 09:28 | ||
Т.е. получается что С++ изначально имеет изъян, потому что позволят это делать... |
| Автор: Lazin 1.7.2009, 09:38 | ||
А разве это не так? Если у тебя объект Foo* можно удалить 2мя способами, то как черт возьми я могу понять, глядя на этот указатель, как мне его удалить, не проследив его жизненный путь до момента создания? Ты хотел-бы разбираться потом в таком коде? Я - нет. |
| Автор: mes 1.7.2009, 10:07 | ||||||
не согласен
Лучше предъявить требование, чтоб создание и удаление были в "пределах видимости" программиста, что в принципе соблюдается у Леопольда: операция удаления "выбрана" рядом с операцией создания. Леопольд, но все же зачем
тоесть вместо garbage_container ипользовать garbage_object. |
| Автор: Lazin 1.7.2009, 10:19 |
никто не мешает мне передать в метод push что угодно мотивируй |
| Автор: mes 1.7.2009, 12:07 | ||||||||
с этим согласен, но это решается путем объеденения создания/удаления в один аллокатор. и если избавиться от контейнера, то интерфейс создания объекта будет такой
где в принципе этот аллокатор можно поставить по умолчанию:
Объекту не желательно знать о способе своего создания и хранения. Для этого есть врапперы (такие как умные указатели) которые задают нужную политику. |
| Автор: Lazin 1.7.2009, 12:58 | ||||
я именно об этом и говорил |
| Автор: mes 1.7.2009, 13:36 | ||
Cpp позволяет очень многое(и именно с этим связаны многие трудности с его освоением), но это не является изъяном. Просто он (cpp) полагается на то, что свобода выражения превыше жестких рамок. |
| Автор: Lazin 1.7.2009, 13:38 |
| кстати, стоит отметить, что сабж - вовсе не сборщик мусора |
| Автор: Леопольд 1.7.2009, 17:47 | ||||||||
Пожалуй да. Но как то его обозвать надо было. Вот я и обозвал, что первое в голову пришло... Пока не думал как можно было-бы заюзать его с пулом, некогда было. Возможно, для этого придётся что-нибудь изменить. Однако если пул singleton, тогда можно будет написать политику удаления и так. Добавлено @ 17:53
А я имел ввиду совсем другое. Какие выгоды от того что способ выделения памяти напрямую зависит от типа? Чем плохо выделять int и при помощи new, и при помощи malloc? Или пользовательский тип? Может мне надо использовать специфический тип, для которого я не хочу вызывать конструктор и деструктор, например. |
| Автор: Леопольд 1.7.2009, 18:06 | ||||||||
Я убрал вчера контейнер и сделал из объектов стек. Каждый объект удаляет предыдущий. Получается на один указатель больше чем без него, потому что надо хранить указатель на последний добавленный объект. Плюс ещё указатели на память. Недостаток в виртуальном деструкторе. Я вчера прогнал через профайлер. Больше всего времени уходит на вызов виртуального деструктора. Вообще, можно ускорить процесс, если сделать отдельный pool для указателей а не выделять для каждого указателя новый кусочек каждый раз. Но мне не хочется, потому что эта штука мне уже не нравится Добавлено @ 18:12
И ничего удивительного. Даже константность можно снять приведением типов. Это С++.
Даже если привязать способ очистки памяти к типу объекта при помощи traits, то что сможет помешать выделить память иначе для этого же объекта? Например, при помощи malloc... Тут уже всё зависит от программиста. Но можно привязать способ очистки к способу выделения памяти а не к типу объекта. Я полагаю, mes, имел ввиду именно это. |
| Автор: mes 1.7.2009, 20:20 | ||||||
Позвольте узнать зачем ? а также хотелось бы услышать какую задачу должен решать Ваш компонент ? (а то обсуждаем зверя о сути которого нам практически ничего неизвестно А зачем Вам вообще обязательный виртуальный деструктор ?
А не объясните ли, как Ваше сравнение вяжется с контекстом замечания ?!
|
| Автор: Леопольд 1.7.2009, 20:29 | ||||||||
Это коллекция разнотипных указателей (отсюда виртуальный деструктор), память на которую они указывают, освобождается одновременно с разрушением объекта хранящего коллекцию. Это единственное предназначение. На мой взгляд, идея о жёсткой связи способа выделения и способа освобождения памяти очень хороша. Добавлено @ 20:31
Именно с контекстом, никак. Но смысл есть... |
| Автор: mes 2.7.2009, 00:35 | ||||
"снять константность" это предназначение инструмента для решения определенной проблемы "передать в метод push что угодно " - это недоработка инструмента, позволяющего создать некоторые непредвиденные проблемы. разницу надеюсь почувствовали
прежде всего сформулируйте, пожалуйста, для чего в Вашем случае необходимо хранить объекты как коллекцию ? |
| Автор: DrHex 2.7.2009, 00:45 | ||
Поддержую..... Для сборки мусора, а точнее освобождению освобождения линамической памяти можно, используются smart-poiner, а фантаций в их реализации куча. Можно есче конечно написать аллокатор, и использовать как для выделения памяти так и для освобождения. Но выделять память, а потом добовлять указатели на эту память в контейнер что бы потом удалить, это нонсанс!!! |
| Автор: Lazin 2.7.2009, 05:53 | ||||
когда речь идет о интерфейсе класса, то желательно, что-бы он был сделан так, что-бы не допустить возможность неправильного использования |
| Автор: Леопольд 2.7.2009, 20:08 |
| Всем спасибо! Противопоставить нечего, потому что сам думаю так же... |