| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Двусвязный список шаблонных классов |
| Автор: BearFear 25.9.2013, 17:30 | ||||
Вопрос вот в чем. Сам не знаю зачем мне это. Хотя цель примерно следующая: сохранить указашки на объекты и удалить если надо объекты вместе с хранителями их указателей. И вместо тысячи слов, быдлокод в студию!
Использование
Насколько опрометчиво использовать подобный подход? |
| Автор: volatile 25.9.2013, 18:58 |
Кто за типами будет следить? вы их правильно удалить даже не сможете, без каста к правильному типу, который никто не знает. я уж не говорю о чем-то другом. Короче, бред. |
| Автор: BearFear 25.9.2013, 19:38 |
| А более подробно можно объяснить? Ведь удаление объекта - это освобождение определенного объема данных, никакой магии. В данном случае размер отслеживается. И о чем то другом уж лучше сказать, а то не очень понятно. Что не так? |
| Автор: akizelokro 25.9.2013, 20:20 |
| пуристы сказали бы ещё, что Int и Сhar мало того, что не очень удачные названия переменных, но их и нужно delete перед завершением программы. Скажу проще, что классический ООП фактически завершается после применения reinterpret_cast. потому что в этом случае проще применять в owner указатели "void *" и без всякого шаблона, а дальше этот указатель приводить к желаемому для вас типу. (Или проще, такой код никому из сторонников объектно-ориентированной парадигмы не понравится, он методологически ближе к "выкрутасам" доброго старого С) |
| Автор: BearFear 25.9.2013, 20:42 |
| Этот код не для того что бы удовлетворить эстетические потребности читающего. Это формулировка и вы сами прекрасно знаете, на скорую руку писать мегасверхкрасивый код смысла нет, он затрется. А на счет реинтерпрета согласен. Это и смущает. Но по факту, 12 байт размер данного по приведенному указателю. Не по приведенному размер такой же. В диспатчере МС просмотрел выделяемые данные. Вроди бы как освобождается норм. За кадром использовал более весомые данные для хранения в шаблоноклассах. Это меня и смутило - неужели работает? Хотелось бы услышать более глубокие ответы, как от профессионалов. Теоретически я и сам не согласен с этим кодом по множеству пунктов и лишний раз напоминать об эстетике каких то моментов... ну господа, это не серьезно. Добавлено через 7 минут и 6 секунд akizelokro, в деструкторе owner (за пределами main - там при прочтении всего сообщения) есть delete тех некрасивых Int и Char. Ребят, если вам не интересно, то ну не пишите и не читайте совсем тогда. Вы и себе время сэкономите и мне не придется как то реагировать на заведомо "недочитанное" вами |
| Автор: BearFear 25.9.2013, 21:02 |
| Высокомерие? |
| Автор: akizelokro 25.9.2013, 21:04 |
Никакого высокомерия. Просто привык, что объекты лучше удалять на том же "уровне" кода, где они были созданы. Для наглядности. |
| Автор: BearFear 25.9.2013, 21:11 |
| Да. Это самый минимальный из минимального. Больше никаких пристроек. Вообще, хотел сделать некое подобие очищалки, для более безопасного вызова экцепшенов. В случае экцепшена опрашивается манагер цепи и он то уже зачищает все новые объекты. В общем самый важный и важнее всех важных вопросов данного топика - есть ли подводные камни именно у этого кода. Не гепотетически, не предполагая всевозможных других использований (не люблю гонку за полтергейстами), а именно то как вот есть. Сам принцип. А небезопасности везде хватает. По дурости как говорится можно и луже утонуть. чтож теперь, бегать за лужами и знаки ставить? Или того лучше дружиников заставить дежурить у луж? Вообще, у меня есть мой парсер, один экземпляр которого я заточил под С++. Он, делает забеги по коду, делает определенные выводы по типам и их использовании и снимает все RTTI в нужных местах. Они обособляются макросами. Но это уже другая история. Решил разнообразиться, вдруг найдется иной способ хранения разных типов в одном месте без последствий в виде утечки. |
| Автор: baldina 25.9.2013, 21:25 | ||
прочитал два раза, но не уверен что понял зачем все это. если цель в
то не проще ли что-нить вроде std::list<std::shared_ptr<boost::any>>>? причем без косяков в отношении типов, о которых сказал volatile. |
| Автор: BearFear 25.9.2013, 22:09 |
| Шаред поинтер сработает в случае SEH? Интересно, где я был когда ввели такую возможность в буст? Если бы я спросил про АНАЛОГИ, может было бы и к месту. Программистов считают людьми, которые воспринимают все слишком буквально. В данных случаях очень много "неявностей" пришлось увидеть. Неизвестные кодеры которые якобы могут вмешаться в код. Предположение о поиске аналогов... Эх, или я не так выражаюсь или собеседники непонятливые. Уважаемые, о том ЗАЧЕМ это нужно я уж как то сам разберусь. Тема ведь не - помогите разобраться зачем мне это и как это использовать? |
| Автор: baldina 26.9.2013, 00:48 |
точно так же, как и ~owner() зачем вам SEH я не спрашиваю, т.к. это не моё дело и вопрос не об этом никто в этом и не сомневается. но раз вопрос задан, нам тоже надо немного понять о чем идет речь. из кода вашего логическая цепь у меня как-то не выстроилась... вопрос был "насколько опрометчиво", не уточняя, с какой позиции рассматривать. скажем, с позиции повторного использования - опрометчиво. с позиции концепции сборки мусора - опрометчиво. с позиции масштабирования - ну если не опрометчиво, то как минимум сомнительно. с позиции С++ после замечания volatile и вашей ремарки, что "удаление объекта это лишь освобождение объема данных" и говорить нечего. |
| Автор: BearFear 26.9.2013, 07:34 |
| Вызвать ~owner из seh хандлера куда проще чем n деструкторов по неизвестным адресам. Поэтому я могу даже гарантировать, что ~owner будет вызван. Ну смысл получается таким - после маин следует стековая процедура создающая синглтон-манагер, который отвечает за создание и очистку двусвязного списка. В используемом окружении все кроме некоторых POD создается динамически. Это уже устоявшийся паттерн, который гарантирует динамическое созданиеотсутствие конструктора копирования и отсутствие ненужных операторов. Есть даже макрос который сокращает путь создания. POD типы, или чаще это структуры, оборачиваются при динамическом создании. Разумеется, метод паттерна может включать код добавления СЕБЯ в список. Это будет рано 1-2 присваиваниям. Если seh - вызывается цепь деструкторов. Достаточно корневому объекту подать команду. Если не seh, то в стековой процедуре инита окружения вызывается та же цепь деструктуров. Но опять же, описаное выше как то изменит наличие ошибки в коде первого сообщения? Нет. Поэтомуя сразу и написал, что сам не знаю зачем оно мне. Что бы вопросов не было. |
| Автор: volatile 26.9.2013, 08:39 | ||
BearFear, просто попробуйте написать процедуру удаления вашей цепочки. А мы посмотрим |
| Автор: BearFear 26.9.2013, 11:49 | ||||
У нулевого звена (адрес которого и хранится в манагере) как и у других звеньев, есть метод delete_chain(). Он будет отвечать за удаление ОТ текущего звена до последнего элемента связи. За срок жизни программы, данная манипуляция будет проводиться 1 раз.
Соответственно, при вызове метода удаления динамического объекта, будет вызываться удаление из цепи. Это будет связывание левого и правого элемента и удаление текущего.
Организация подобного в виде массива накладно. Свести в один массив кучу указателей а потом еще и пытаться туда дописать... А такая штуковина не требует индексации, поэтому тут совершенно ненужен учет количества. Все что смущает, это верность следующего утверждения: одинаково ли удалятся шаблонные объекты, если был вызван метод класса не зависящий от параметров шаблонного класса, который в свою очередь дернул деструктор внутри себя. Если это так, то ... то круто! Более навороченного варианта и не требуется. |
| Автор: xvr 26.9.2013, 12:00 |
| Во первых ваш код не скомпилится - использовать просто owner в нем самом нельзя, т.к. owner это шаблонный класс, и должно быть как минимум owner<какой то тип> Исли заменить все owner на owner<type>, то все соберется, но тут начнутся проблемы в другом месте. В том, где у вас reinterpret_cast<owner<int>*>. Проблема в том, что delete не только освобождает память (это он сделает правильно), но и вызывает деструктор. Если у вас в owner попадут не char/int, а классы со своими деструкторами, вы получите вызов не того деструктора |
| Автор: BearFear 26.9.2013, 12:45 |
| xvr, а повлияет ли тот факт, что в шаблонном классе хранится не данное, а типизированный указатель? Он же по идее должен быть лонг указателем грубо говоря? Я имею ввиду, что шаблонный овнер содержит не данное, поэтому тип параметризации становится неважным. Или я ошибаюсь? Ведь шаблонный класс (и его часть - деструктор) отвечает ведь только за сам шаблонный объект. А шаблонный объект... стало быть при реинтерпретации будут указаны неверные размеры хранимого данного? Тогда текущий вопрос имеет переформулировку. Влияет ли реинтерпретация типа шаблонного объекта на вызов деструктора встроенных в него полей (указателей на динамические данные)? Без сомнений, если поле будет частью объекта (не указатель), то это приведет к удалению недостаточного количества данных в лучшем случае. В худшем, к удалению лишних данных, не относящихся к данному объекту. |
| Автор: akizelokro 26.9.2013, 13:09 | ||
| Вчера хотел вякнуть про удаление объектов и необходимость перегрузки delete(). Но я не особо лихой программер, и что там функция free будет делать и как всё это прописать получше. Хотя там же опять загвоздка, что данные создаются не на том "уровне". На "том" уровне можно было бы поизвращаться ещё. А так проблемка. Хотя и там тоже некоторая проблемка (надо вспоминать, как в С выделение памяти работает и всё такое прочее) Добавлено @ 13:14
Здесь вопрос возникает, насколько много не относящихся. Утверждение, что всё должно работать, просьба дезавуировать. БЫло написано, когда код до конца не дочитал и не предполагал, что объекты будут удаляться в деструкторе owner<> |
| Автор: volatile 26.9.2013, 14:27 | ||
Типизированный указатель, тип которого не соответствует реальному типу данных. |
| Автор: BearFear 26.9.2013, 15:09 |
| Да, но ведь как не крути, это всего лишь лонг. Типы отслеживаются только на стадии компиляции. За пределами компилятора можно лишь частично узнать тип, скорее всего без преобразований туда-сюда (я имею ввиду преобразования прямо в лоб, не динамик-касты). Следовательно, программе должно быть пофигу на что указывается лонг. Могут быть оверхеды, об их существовании ходят мифы, но я так и не понял есть ли они. Если они есть, то дело плохо. Но чаще я встречал инфу о том, что С++ один из немногих языков не имеющий оверхедов касающихся типов. Следовательно, имеется ряд объектов: 1 - объект владеющий элементом цепи 2 - элемент цепи владеющий данным 3 - данное При удалении элемента цепи взаимодействуют 1>2 затем 2>3. То есть, связи между 1 и 3 нет, и объект 1 и не должен знать о том что содержит 2й. Единственное что может повлиять - если деструктор в памяти принимает аргумент при вызове, который как то указывает на тип, что в свою очередь влияет на размер удаляемого данного. Но по мне это не должно быть так. Ну я бы так не стал делать. Потому что в этом случае, неправильный вызов деструктора привел бы к плачевным последствиям. Это все балабольство конечно, мысли в слух. |
| Автор: volatile 26.9.2013, 18:40 |
BearFear, у вас не могут быть оверхеды, а точно будут сегфолты. Вы кастанули указатель, и я не вижу где вы его кастуете обратно, к реальному типу. пишете много букв... как обчно, смысла в них нет. |
| Автор: akizelokro 26.9.2013, 19:14 |
| У вас здесь может быть всё, что угодно. Вы здесь говорите на разной терминологии. Один в рамках чистого ООП, при котором код передаётся спокойно от одного к другому программисту (и пишется исходя из этого). И достаточно проблематично, кстати, написать неправильно код по высвобождению памяти для обьектов в принципе правильно оформленного двусвязного списка. Другой пишет код в стиле "выкрутасного" С в ООП парадигме и при этом запрашивает совета большого числа программистов, отрицая сам факт, что его код будут просматривать (и фактически применять другие программисты). Наряду логический дискурс. Что интересно. Можно было бы написать и так, если вспомнить, как же я всё-таки выделял память лет 10 назад для Сшных программ, и можно ли там правильно освобождать память, исходя только из одного указателя (или хэндлера на выделенный блок памяти, чтобы вне зависимости от размера объекта, память высвобождалась правильно). Вне зависимости от того, какой объект вы собираетесь подвести под перегруженный (должен быть перегруженный) delete(). Вообще сама задача нисколько не похожа на wrappers для указателей, в ней берутся уже неизвестно где (на уровень кода выше) объекты, предварительно построенные на предположении о том, что память для них выделена динамически (ладно, для чистоты эксперимента поверим) и сам класс (обрывок кода по сути) должен правильно удалить этот объект. Либо, в предположении автора, объекты могут удаляться неправильно, но автор сделает так, что последствия будут незначительны А можно для попытки изврата и привести примеры, где автор сделает так, что последствия усугубят "undefined behaivour" настолько, что слетит система. |
| Автор: BearFear 26.9.2013, 23:02 |
| volatile, Из ничего всего не бывает. Если для вас букв слишком много, вас никто не заставляет их читать. Впрочем вы можете и не доводить до конца формулировку вашего кода. К чему много букв кода, когда можно просто писать un in v = ; И если есть какие то детальные понимания у вас, то изложите. Из вашей немногословности, лично я мало что могу понять, все выглядит как простые выкрики из толпы: ".... бред..... фигня.... не получится....". Ну если вы владеете истиной, откройте ее для меня, я за это скажу много раз спасибо. |
| Автор: BearFear 26.9.2013, 23:39 |
| Ну неужели только наследование? Ведь все очень рядом и близко, неужели в С++, для решения такой простой задачи надо использовать одну из возможностей языка под названием ООП? Или костыли привязанные бинтами к голове. Работа с типами завершается до запуска программы. Почему бы не создать простейшую возможность проведения типа. Ведь сторонними средствами написанными на том же С++ я вполне могу дозавершить это дело. Но делать лишний прогон сырцов через свои тулзы, затем пропускать новые образцы через препроцессор, компилятор, линковщик. А если это шаредлиб, то сначала тулза, препроцессор, ... а потом и вовсе другое приложение зависимое от либы. Ну это же пипец одним словом. Уже не говоря о красивешем мейке, который ваще давно пора заменить на что то более человекоподобное. Короче я ушел пить. В понедельник может залезу в оллидбг, ща уже чот не хочется ковыряться в этом. Ну все это к черту! |
| Автор: volatile 27.9.2013, 00:27 | ||||
Так в С++ делать НЕЛЬЗЯ! (у вас если отбростить кучу застилающего хлама, делается именно так) Вы это понимаете? |
| Автор: BearFear 27.9.2013, 07:57 |
| Такой большой массив за один раз не получится выделить. В вашем коде, переназначается данное указателя. У меня такого не происходит. А вот то что может удалиться значение ПОСЛЕДНЕГО каста... в это я еще поверю. Я и сам знаю что такое могло произойти. В общем ладно, оставлю обсуждение до понедельника, там может (если руки дойдут) на асме поковыряюсь, может вставками на асме добью это дело. Просто наследование и удаление через суперкласс с виртуальным деструктором не очень хочется. Не все классы получится наследовать. И сам факт виртуального деструктора, там же как то поиск производится, на это уходит времени куда больше, чем при прямом обращении к не виртуальному деструктору. |
| Автор: mes 27.9.2013, 08:31 |
BearFear, храните полиморфный deleter (например void (*deleter)(void *)) в паре с указателем и будет вам счастье для определения делетера используется шаблон. подобное решение можно применять всегда , когда на месте применения важен не тип, но действие.. подробнее поиском по "type erasure" |
| Автор: BearFear 27.9.2013, 08:32 |
| mes, о, понял о чем вы. Сейчас голова проснется, попробую. Кстати говоря, утром почему то была уже идея, организовать удаление не частью класса, а отдельной процедурой в стеке. Никак не мог сформулировать. mes, вы меня правильно поняли. |
| Автор: mes 27.9.2013, 08:33 | ||
это избыточное решение.. Добавлено @ 08:38 вот тут пример поведния : http://forum.vingrad.ru/forum/topic-326256/hl/erasure/index.html |
| Автор: BearFear 27.9.2013, 08:38 |
| mes, ДА! ООП в данном случае - это очень много действий вокруг и около! |
| Автор: mes 27.9.2013, 08:40 |
не ооп, а использование встроенной виртуальности.. хотя и так тоже можно, но технология называется по другому... также имеется пример по приведенной выше ссылке |
| Автор: BearFear 27.9.2013, 08:50 |
| Только вот сообразить не могу. Ок есть шаблонная процедура которая на входе определяет тип и удаляет его. С удалением проблем нет. Но что в нее подать и откуда? Сохранить данные в ряд можно либо через void*, либо... Ладно, сайчас кофе подействует, до работы доберусь, должно что то родиться. |
| Автор: mes 27.9.2013, 09:05 | ||
что то типо этого :
|
| Автор: volatile 27.9.2013, 11:10 | ||
Хех, как будто проблема удаления это главная проблема
О чем-то другом еще подумайте, если вы с объктами еще что-то хотите делать, кроме удаления |
| Автор: BearFear 27.9.2013, 12:29 |
| В первом сообщении еще было о том, что удаление и хранение разных типов в списке является главной проблемой. Если нет потребности в ином, зачем иное прописывать? Чтоб просто так было и плодились ошибки? |
| Автор: BearFear 27.9.2013, 13:10 |
| mes, стало быть тип хранится в статическом коллбэке и сохраняется туда на стадии компиляции. Тип хранимого данного в этот момент не важен. Спасибо большое! Думаю Скептикам вроди volatile есть что поиметь ввиду. Ыть |
| Автор: mes 27.9.2013, 14:13 | ||
|
| Автор: BearFear 27.9.2013, 17:15 |
| mes, volatile, akizelokro, xvr, baldina, спасибо вам большое за помощь! |
| Автор: BearFear 28.9.2013, 03:58 |
| Еще одна особенность. Данный метод пригоден для стековых данных. Однако, перегрузка delete все решит. Либо френд (наверно будет безопаснее). |
| Автор: mes 28.9.2013, 10:50 | ||
Добавлено через 47 секунд
? |
| Автор: BearFear 28.9.2013, 18:48 |
| Динамическое создание будет выглядеть немного по иному, не так как было написано mes. Если действовать по канонам только динамических объектов (сокрытие конструктора, деструктора и прочих методов), то удаление может происходить либо через производный класс и протектед, либо через перегрузку делит, либо через френд. |
| Автор: mes 28.9.2013, 20:34 | ||||
о время ! о нравы !
мысль хоть и с трудом, но стала понята... однако далека от истины, хотя частичку проблемки отражает.. полагаю вас тянет ознакомиться с SFINAE.. |
| Автор: BearFear 29.9.2013, 02:12 |
| Хм, о таком маневре не знал. Спасибо за подсказку. Подстановка вызова метода в области параметра (надеюсь дело не ограничено только полями, так как нашел пример с полями. Про методы там не писалось). Попробую поискать еще побольше инфы. |
| Автор: mes 29.9.2013, 10:39 |
с методами такая же история |
| Автор: BearFear 29.9.2013, 21:37 |
| Тогда ваще ГУД! |