Я пытаюсь написать простой класс менеджера событий и слушателей для игрового движка. В обычной реализации (т.е. McShaffry) менеджер событий регистрирует слушателей, которые в принципе сохраняют shared_ptr для слушателя как частный член.
Я видел, как во многих случаях люди говорили, что shared_ptr и лайки следует избегать (например, Вот). Таким образом, я пытаюсь найти способы реализации менеджера событий, не разделяя владения слушателями.
Один из методов, о котором я подумал, — это присвоить слушателям уникальные идентификаторы и зарегистрировать их в менеджере событий. Затем слушатели отвечают за «запрос» менеджера событий после его обновления, если какие-либо события доступны под их идентификатором.
Я хотел бы спросить, существуют ли более чистые и / или стандартные методы, чтобы избежать совместного владения в этом случае, но также и в целом. Например, у меня такая же проблема со слушателями. Слушатели должны хранить указатель на своего родителя (или объект, для которого они слушают), чтобы они могли вызывать его методы при обработке события.
Как говорится в комментарии Мата, нет причин не использовать умные указатели в общем. Тем не менее, предупреждающее предупреждение делает кажется, применимы в вашей ситуации: насколько я понимаю, вы не имеете совместного владения; менеджер мероприятия является единоличным владельцем слушателей. shared_ptr
Таким образом, здесь неуместно.
Альтернативой было бы использовать unique_ptr
которая во многих отношениях является другой стороной shared_ptr
монета. Но в зависимости от того, как вы моделируете слушателей, этого можно избежать, просто сохранив бетон экземпляры менеджеру мероприятия. Без более подробного описания невозможно сказать, нужны ли вам вообще указатели, кроме если тогда они вам не нужны, да, совет применим: не используйте (умные) указатели, когда конкретные объекты подойдут.
Наконец, если ваши слушатели являются объектами, чьей собственностью управляют в другом месте, рассмотрите возможность использования сырье указатели на эти объекты: в этом случае менеджер событий вовсе не является владельцем объекта — ни единственным, ни общим владельцем. Хотя это было бы для меня предпочтительным способом, требуется тщательный анализ продолжительности жизни слушателей, чтобы менеджер событий не указывал на слушателей, которых больше не существует.
shared_ptr
имеет тенденцию быть чрезмерным; это часто рекомендуется, например, для SO как решение смутно заявленных проблем с указателями. Он не является заменой для хорошего дизайна и не должен использоваться, если не существует проекта, основанного на понимании проблем времени жизни объекта в написанном коде.
Из личного опыта, shared_ptr
Это отличный, но иногда не самый подходящий инструмент для работы. Если код полностью находится под вашим контролем, 99,9% времени, shared_ptr
вероятно, сделает вашу жизнь проще. Вы должны убедиться, что вы не делаете, думает, как:
Foo *f = new Foo();
shared_ptr<Foo> fptr(f);
shared_ptr<Foo> fptr2(f);
Это приведет к освобождению памяти для f либо fptr1
или же fptr2
, Вместо этого вы хотите сделать что-то вроде:
Foo *f = new Foo();
shared_ptr<Foo> fptr(f);
shared_ptr<Foo> fptr2 = fptr;
Во втором случае присвоение одного общего указателя другому будет увеличивать счетчик ссылок.
Еще одно место, где вы можете столкнуться с проблемами shared_ptr
если вам нужно передать голый указатель на функцию (это может произойти, если вам нужно передать этот в качестве первого параметра метода, или вы полагаетесь на стороннюю библиотеку). Вы можете получить голый указатель от shared_ptr
, но вам не гарантируется, что адрес памяти, на который он указывает, все еще будет, поскольку счетчик ссылок не будет увеличен.
Вы можете обойти это, сохранив дополнительный shared_ptr
Хотя это может быть хлопот.
Существуют и другие формы умных указателей. Например, OpenSceneGraph имеет ref_ptr
с которым легче работать, чем с shared_ptr
, Единственное предостережение — все объекты, на которые он указывает, должны спускаться с Referenced
, Тем не менее, если вы согласны с этим, я думаю, что намного сложнее случиться с действительно плохими вещами.
В некоторых случаях shared_ptr
является чрезмерным или не соответствует желаемой семантике (например, передача права собственности).
Что вам нужно сделать, это посмотреть на свой дизайн и посмотреть, какая модель собственности вам нужна. Если вам нужно / нужно совместно владеть, просто используйте shared_ptr
смоделировать это. Если общее / ref подсчитанное владение не подходит, используйте другой умный указатель.
Разве ваш случай не подойдет для хорошего использования auto_ptr
описано здесь: http://www.gotw.ca/publications/using_auto_ptr_effectively.htm (гуру недели «эффективно использую auto_ptr)
Насколько я понимаю, вы создаете слушателя, а затем отдаете его менеджеру событий. Так что менеджер событий можно рассматривать как «слив».
С техникой auto_ptr ваш менеджер событий может полностью и безопасно взять на себя ответственность за слушателя, которого вы ему предоставите.