c++ Observer Pattern: необработени указатели срещу shared_ptr?

В процес съм на преобразуване (поне) на част от моя код към използване на shared_ptr. Въпреки това срещам проблем с модела Observer, който използвам.

Имам клас презентатор (Model View Presenter), който прилага модела 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_ptrs навсякъде.

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
Идвам от C# и наистина получавам смесени съобщения относно 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_ и темата трябва да бъде 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