С++ Шаблон наблюдателя: необработанные указатели против shared_ptr?

Я нахожусь в процессе преобразования (по крайней мере) части моего кода в использование shared_ptr. Однако у меня возникла проблема с шаблоном Observer, который я использую.

У меня есть класс презентатора (представитель представления модели), который реализует шаблон Observer и получает уведомление, когда происходят определенные события. Я написал общие классы Subject/Observer, от которых может наследовать любой класс. Метод обновления выглядит примерно так:

void MyPresenter::Update(Subject *subject)
{
    if(subject == myService_)
    {
        DoSomething();
    }
    else if(subject == myOtherService_)
    {
        DoSomethingElse();
    }

}

Это работало нормально, пока я не преобразовал myService_ (член класса MyPresenter) в std::shared_ptr. Теперь выражение (subject == myService_) больше недействительно.

Я могу в конечном итоге преобразовать все в shared_ptr, но до тех пор есть ли простой способ поддерживать как необработанные указатели, так и shared_ptr с шаблоном Observer? В идеале я бы хотел, чтобы шаблон наблюдателя не зависел от реализации указателя наблюдателя, но, возможно, это невозможно. Как я могу это исправить?

ОБНОВЛЕНИЕ

Должен ли интерфейс наблюдателя шаблона наблюдателя принимать общий указатель? Или лучше оставить его как необработанные указатели? В настоящее время у меня есть:

class Subject;

class Observer
{
public:
    virtual ~Observer() {}
    virtual void Update(Subject *subject) = 0;

protected:
    Observer() {}
};

person User    schedule 31.10.2011    source источник


Ответы (3)


Вы можете использовать член get shared_ptr, который возвращает необработанный указатель, который обертывает shared_ptr:

subject == myService_.get()

В общем, я бы не советовал слепо преобразовывать все необработанные указатели в shared_ptrs. Вы всегда должны думать о том, действительно ли окружающий объект владеет объектом, на который указывает объект (а совместное владение по-прежнему является владением). Иногда std::unique_ptr (хотя я не знаю, есть ли это уже у tr1, иначе std::auto_ptr) является лучшим выбором, если это строгое владение или также просто необработанный указатель, если это не владение.

Но в интерфейсах, особенно в аргументах функций и возвращаемых значениях, необработанные указатели часто являются лучшей идеей, чем использование интеллектуальных указателей и, таким образом, снижение универсальности (а также производительности, хотя и незначительно, но тем более для shared_ptr).

ПРИМЕЧАНИЕ: я знаю, что это тот же ответ, что и уже существующий, но я отчаянно чувствовал необходимость просто не предлагать использовать shared_ptr повсюду.

person Christian Rau    schedule 01.11.2011
comment
Используя Visual Studio 2010, я только что обнаружил, что могу использовать std::shared_ptr вместо std::tr1::shared_ptr. Также доступен unique_ptr. - person User; 01.11.2011
comment
Я пришел из С# и действительно получаю смешанные сообщения о shared_ptr. С одной стороны, люди говорят, что очень сложно написать код без утечек, особенно если учесть различные сценарии исключений, а с другой стороны, люди говорят, что не используйте его слишком часто. Хотя, помимо недостатков производительности, я не слишком понимаю недостатки использования интеллектуальных указателей. - person User; 01.11.2011
comment
@User Это снижает гибкость, так как вам всегда нужно передавать shared_ptr, если он нужен аргументу функции, хотя это просто не обязательно. Кроме того, использование shared_ptr-члена, когда нет семантики владения (будь то просто совместное владение), в лучшем случае концептуально неверно, а в худшем случае приводит к простым ошибкам (старайтесь не использовать интеллектуальные указатели для не динамически выделенных объектов). - person Christian Rau; 01.11.2011
comment
@User Конечно, умные указатели часто являются очень хорошей идеей, но вам просто нужно знать об их использовании и его последствиях. - person Christian Rau; 01.11.2011

Чтобы это работало, myService_ и subject должны быть shared_ptr. В противном случае вы можете попробовать сравнить это так, если subject и shared_ptr указывают на один и тот же объект.

  subject == myService_.get()

В противном случае попробуйте изменить все указатели на shared_ptr.

person tune2fs    schedule 31.10.2011

Почему бы просто не позволить модели наследовать от std::enable_shared_from_this. Если право собственности в любом случае является общим, то shared_from_this может быть возвращено из (возможно, виртуального) метода модели. Остерегайтесь, однако это имеет некоторые ограничения для конструктора модели.

person user1550088    schedule 04.06.2013