1) Вручную отслеживаете? ("Ага, этот объект прибивается раньше этого, значит упасть не должно... э... я что-то упустил...")
2) Делаете железобетонные "правила владения"? ("При создании объекта A указываете в качестве родительского объект B. Я сказал, B, а не C, вашу мать!")
3) Везде пихаете boost::shared_ptr? А код, утыканный shared_ptr<>? А многопоточность? А производительность? А циклические ссылки? А структуры с указателями, в которых предполагаются голые указатели?
4) Используете garbage collector? Но он же точным быть не может? А производительность? А кроссплатформенность?
Как правильно-то? Кошерно, православно, канонично? Просветите меня, невежественного, плиз.
Здравствуйте, Kerbadun,
K>Как вы реально работаете с памятью в C++?
--
Как только принимается решении динамически выделить память в некотором месте программы, сразу же за этим определяется место, где эта память должна быть освобождена. Пока это не сделано и не отлажено, дальнейшая функциональная разработка кода приостанавливается.
Точно такой же подход используется и при работе с другими ресурсами (файлы, Com-интерфесы и т.п.).
Здравствуйте, Kerbadun, Вы писали: K>Как вы реально работаете с памятью в C++?
А вы как реально с числами работаете? Складываете их, отнимаете, умножаете или делите?
Зависит от задачи. От использования динамической памяти требуется две вещи -- работать быстро и не допускать утечек. Для последнего применяется RAII, понимание, кто владеет памятью и кто должен удалять. Для локальных временных объектов -- scoped_ptr/scoped_array или auto_ptr/vector, для более продолжительного времени жизни -- объект владеет своими членами-указателями (лучше теми же scoped_ptr/scoped_array/auto_ptr/vector), при запутанных связях и смене владельца -- умные указатели (shared_ptr или простые самодельные). Для скорости могут перегружаться new/delete для некоторых типов, или даже использоваться разные пулы для разных подмножеств.
я и не рассматривал, если вы это имеете в виду под "безопасными обертками". С этим, в общем-то, в C++ все хорошо. Но это и так достаточно тривиальный случай управления памятью, с ним и в C особых проблем не возникает, так как вызов парного метода free() не такая большая трудность, и если его забыть, это не влечет каких-то глобальных головняков.
Проблемы начинаются в более сложных случаях (из коих реальные программы состоят чуть менее, чем полностью): при использовании указателей на интерфейсы, колбеки-функции-методы, события и т.п., когда времена жизни объектов не ограничиваются одной функцией, и граф ссылок не является деревом.
И, конечно, адская головная боль начинается при использовании многопоточности.
И еще, по-моему, "использование четкой политики времени жизни объекта" относится к ручному управлению памятью, так как при автоматическом (e.g. GC) такая политика просто не нужна.
я и не рассматривал, если вы это имеете в виду под "безопасными обертками". С этим, в общем-то, в C++ все хорошо. Но это и так достаточно тривиальный случай управления памятью, с ним и в C особых проблем не возникает, так как вызов парного метода free() не такая большая трудность, и если его забыть, это не влечет каких-то глобальных головняков.
Я бы так написал.
X x;
x.Do();
K>Проблемы начинаются в более сложных случаях (из коих реальные программы состоят чуть менее, чем полностью): при использовании указателей на интерфейсы, колбеки-функции-методы, события и т.п., когда времена жизни объектов не ограничиваются одной функцией, и граф ссылок не является деревом.
Чуть более сложные случаи стараюсь свести к простым случаям.
K>И, конечно, адская головная боль начинается при использовании многопоточности.
Не замечал.
K>И еще, по-моему, "использование четкой политики времени жизни объекта" относится к ручному управлению памятью, так как при автоматическом (e.g. GC) такая политика просто не нужна.
K>Как вы реально работаете с памятью в C++?
K>2) Делаете железобетонные "правила владения"?
Да. "Железобетонность" по максимуму перекладывается на компилятор. Но сначала те самые правила владения нужно определить. А вот это в большинстве случаев представляет собой некоторую проблему... Но это уже тема для другого разговора. Для затравки — http://home.pipeline.com/~hbaker1/Use1Var.html
K>Как правильно-то?
Критерии "правильности" в студию.
Здравствуйте, Kerbadun, Вы писали: K>Проблемы начинаются в более сложных случаях (из коих реальные программы состоят чуть менее, чем полностью): при использовании указателей на интерфейсы, колбеки-функции-методы, события и т.п., когда времена жизни объектов не ограничиваются одной функцией, и граф ссылок не является деревом.
Разбейте граф на несколько больших подграфов-деревьев и проблема упростится.
K>>И еще, по-моему, "использование четкой политики времени жизни объекта" относится к ручному управлению памятью, так как при автоматическом (e.g. GC) такая политика просто не нужна.
M>Возможно , это же ваша классификация.
Ну, а у вас что за классификация, позвольте осведомиться? Или у вас "четкая политика времени жизни объекта" автоматически составляется?! Oh, wow!
K>>Проблемы начинаются в более сложных случаях (из коих реальные программы состоят чуть менее, чем полностью): при использовании указателей на интерфейсы, колбеки-функции-методы, события и т.п., когда времена жизни объектов не ограничиваются одной функцией, и граф ссылок не является деревом.
MOP>Разбейте граф на несколько больших подграфов-деревьев и проблема упростится.
Не разбивается. Если б можно было разбить, разбили бы.
K>>Как правильно-то? ЮЖ>Критерии "правильности" в студию.
Так я их и не знаю, потому и спрашиваю.
В идеале, ясен конь, — чтобы никогда не нужно было думать о том, где выделяется объект, никогда ничего не текло, не падало и всегда быстро работало. Конечно, не уверен, что в C++ (или в любом другом языке) все эти условия достижимы.
Здравствуйте, Kerbadun, Вы писали:
K>>>Проблемы начинаются в более сложных случаях (из коих реальные программы состоят чуть менее, чем полностью): при использовании указателей на интерфейсы, колбеки-функции-методы, события и т.п., когда времена жизни объектов не ограничиваются одной функцией, и граф ссылок не является деревом.
MOP>>Разбейте граф на несколько больших подграфов-деревьев и проблема упростится.
K>Не разбивается. Если б можно было разбить, разбили бы.
На самом деле, конкретной ситуации с такой проблемой, чтобы я не мог решить, особо нет, так как я, все-таки, не совсем туп, и с грехом пополам использую примерно те же "полуавтоматические" методы, что и отметившиеся здесь.
В качестве довольно "злобного" примера можно привести, скажем, UI-ный движок и сам UI на C++ с системой событий, привязкой данных и многопоточностью. Думаю, все, кто пытался делать UI-ный движок на C++, знает, что даже у самых матерых гуров в итоге все равно получается различного вида порно в сочетании с шаблонными и метапрограммными извращениями. Про QT я в курсе, если вы считаете, что использование отдельного препроцессора (а он используется в том числе для системы сигналов-слотов) — это нормальное решение, то я с вами, в принципе, соглашусь, но замечу, что это решение вообще выходит за рамки C++, а значит, видимо, в рамках C++ они его не осилили.
Само по себе дерево контролов, может, и не создает проблем (хотя необходимость явного указания parent'а в некоторых UI-движках я считаю унылым артефактом), но когда туда добавляются события, произвольная привязка данных и многопоточность, граф перестает быть древовидным и однопоточным, и появляется необходимость в четком подходе к управлению памятью.
В принципе, вроде бы garbage collection — практически идеальное решение для UI-ного движка, решающее все проблемы, но в C++ его нормального нет, да и вообще кто его там знает насчет его эффективности на мобильных платформах (хотя в андроиде и Windows Phone вроде применяется, и ничего). Ну и при большом графе объектов тоже вопрос.
Ну а кроме этого примера, меня вообще смущает общая "бессистемность" и "гуманитарность" управления памятью в C++. Тут у нас ссылка, тут указатель, тут умный указатель, тут по значению объект создается, тут рыбу заворачивали. Ну и "четкие политики по времени жизни объектов" как-то не вызывают энтузиазма ("Вася, епт, такую твою, я те говорил, шо надо пэрентов добавлять или не говорил?!" — так достигается "четкость", видимо).
Ну и, наконец, получается, что в C++ просто нет равномощной альтернативы сборке мусора в управляемых языках. Подсчет ссылок засоряет код, не работает с циклическими ссылками (а они получаются на раз-два даже при самой дистиллированной архитектуре, кто бы что не говорил) и неэффективен (особенно в многопоточном применении).
Здравствуйте, Kerbadun, Вы писали:
M>>Опиши конкретную ситуацию.
K>На самом деле, конкретной ситуации с такой проблемой, чтобы я не мог решить, особо нет, так как я, все-таки, не совсем туп, и с грехом пополам использую примерно те же "полуавтоматические" методы, что и отметившиеся здесь.
K>В качестве довольно "злобного" примера можно привести, скажем, UI-ный движок и сам UI на C++ с системой событий, привязкой данных и многопоточностью. Думаю, все, кто пытался делать UI-ный движок на C++, знает, что даже у самых матерых гуров в итоге все равно получается различного вида порно в сочетании с шаблонными и метапрограммными извращениями.
Если оно достигает цели и финальный код (а не тот библиотечный ужас, что под ним) получается простым и самоочевидным, то в чем проблема?
K>Про QT я в курсе, если вы считаете, что использование отдельного препроцессора (а он используется в том числе для системы сигналов-слотов) — это нормальное решение, то я с вами, в принципе, соглашусь, но замечу, что это решение вообще выходит за рамки C++, а значит, видимо, в рамках C++ они его не осилили.
Они не знали про (или тогда его просто не было) Boost.Signal. На них все это замечательно делается, у меня, по крайней мере, никаких проблем с ними не было. Но все зависит от приложения, ессно, времени жизни данных и т.д.
K>Само по себе дерево контролов, может, и не создает проблем (хотя необходимость явного указания parent'а в некоторых UI-движках я считаю унылым артефактом), но когда туда добавляются события, произвольная привязка данных и многопоточность, граф перестает быть древовидным и однопоточным, и появляется необходимость в четком подходе к управлению памятью.
K>В принципе, вроде бы garbage collection — практически идеальное решение для UI-ного движка, решающее все проблемы, но в C++ его нормального нет, да и вообще кто его там знает насчет его эффективности на мобильных платформах (хотя в андроиде и Windows Phone вроде применяется, и ничего). Ну и при большом графе объектов тоже вопрос.
Есть же gc-решения для С++. Вы их пробовали применять?
K>Ну а кроме этого примера, меня вообще смущает общая "бессистемность" и "гуманитарность" управления памятью в C++. Тут у нас ссылка, тут указатель, тут умный указатель, тут по значению объект создается, тут рыбу заворачивали.
Бессистемность в голове, а не в С++.
Как можно перепутать создание объекта по значению с им же по расшаренной ссылке — от меня ускользает, если честно.
K>Ну и "четкие политики по времени жизни объектов" как-то не вызывают энтузиазма ("Вася, епт, такую твою, я те говорил, шо надо пэрентов добавлять или не говорил?!" — так достигается "четкость", видимо).
так надо просто делать интерфейс, который исключит возможность неправильного использования. Т.е. нет парентов — не компилируется.
K>Ну и, наконец, получается, что в C++ просто нет равномощной альтернативы сборке мусора в управляемых языках. Подсчет ссылок засоряет код, не работает с циклическими ссылками (а они получаются на раз-два даже при самой дистиллированной архитектуре, кто бы что не говорил) и неэффективен (особенно в многопоточном применении).
Здравствуйте, Kerbadun, Вы писали:
K>>>Как правильно-то? ЮЖ>>Критерии "правильности" в студию.
K>Так я их и не знаю, потому и спрашиваю.
K>В идеале, ясен конь, — чтобы никогда не нужно было думать о том, где выделяется объект, никогда ничего не текло, не падало и всегда быстро работало. Конечно, не уверен, что в C++ (или в любом другом языке) все эти условия достижимы.
Такому набору критериев удовлетворяет только сборка мусора.
Если убрать первое ("никогда не нужно было думать о том, где выделяется объект") и все-таки продумать политику владения и времен жизни, то остальное можно отдать на откуп соответствующим политике механизмам.