2011-02-02 3 views
6

ОК, я начал использовать общие указатели и передавать общие указатели как можно больше. Больше не конвертировать в исходные указатели. Это работает хорошо, но в данном конкретном случае:shared_ptr и этот указатель

Предположим, у нас есть класс, который также является наблюдателем от другого класса, например:

class MyClass : public IObserver 
    { 
    public: 
     MyClass (std::shared_ptr<SomeOtherClass> otherClass); 
     void DoSomethingImportant(); 
    private: 
     std::shared_ptr<SomeOtherClass> m_otherClass; 
    }; 

Этот класс используется, как это в моем приложении:

std::shared_ptr<MyClass> myInstance(new MyClass(otherInstance)); 
... 
myInstance->DoSomethingImportant(); 

MyClass получает общий указатель на другой класс и сохраняет его в своем элементе данных m_otherClass. В методе DoSomethingImportant экземпляр MyClass выполняет множество важных задач, включая регистрацию себя как наблюдателя на m_otherClass, например:

m_otherClass-> registerObserver (this);

Проблема заключается в том, что метод registerObserver определяется следующим образом:

недействительного registerObserver (станд :: shared_ptr наблюдателя);

Он ожидает общий указатель, но «это» - это необработанный указатель, а не общий.

Я вижу три пути решения этого:

  • Найти трюк, чтобы преобразовать обычный указатель на общий указатель (см вопроса convert pointer to shared_ptr), но ответы на этот вопрос только предложить, чтобы скопировать общие-указатели , а не о том, как фактически преобразовать указатель в общий указатель.
  • Передайте общий указатель на наш метод, например: «myInstance-> DoSomethingImportant (myInstance);» что кажется немного глупым.
  • Поместите часть наблюдателя в отдельный класс. Это похоже на излишний, и может сделать класс труднее понять.

Эта проблема делает очевидным, что общие указатели - это просто дополнение к C++ (я не думаю, что у вас такая же проблема на других языках/средах, таких как C# (или .Net вообще) и Java).

Любые другие предложения или рекомендации по устранению этой ситуации?

+2

Вы не можете использовать 'enable_shared_from_this'? (См. [Получение Boost shared_ptr из этого] (http://stackoverflow.com/questions/142391/getting-a-boostshared-ptr-for-this)) –

+3

Кто это отрицает этот вопрос и все ответы? Неужели это такой глупый вопрос? – Patrick

+0

Я иногда удивляюсь ... если некоторые люди просто не пытаются получить значок http://stackoverflow.com/badges/7/critic?userid=147192 –

ответ

8

Возможно, что вам нужно enable_shared_from_this и shared_from_this. Документы: here

Обратите внимание, что вы не можете использовать shared_from_this, пока конструктор не будет полностью завершен, а объект уже принадлежит другому shared_ptr.

struct test : boost::enabled_shared_from_this<test> 
{ 
    test() { 
     // shared_from_this(this); // error, still not owned by another shared_ptr 
    } 
    boost::shared_ptr<test> shared() { 
     return shared_from_this(this); 
    } 
}; 
int main() { 
    test * t = new test; 
    // boost::shared_ptr<test> p = t->shared(); // error, not yet owned by other shared_ptr 
    boost::shared_ptr<test> owner(t); 
    boost::shared_ptr<test> p = t->shared();  // [*] ok, "owner" owns the object 
} 

[*] Эта часть примера глупо, вы можете просто скопировать владельца в р, вместо вызова метода.Это просто замечается, когда это нормально или не называть shared_from_this внутри методов test.

+0

Это действительно то, что я ищу. Есть ли аналогичное решение для C++ 0x shared_ptr? (Я использую Visual Studio 2010, не используя Boost). У вас есть идея о влиянии на объем памяти? Сохраняет ли он общий указатель на себя или как это работает? – Patrick

+0

Обнаружено, что в Visual Studio 2010 действительно есть enable_shared_from_this. Спасибо. – Patrick

+0

Усиление и предстоящие стандартные библиотеки очень похожи, если не совсем то же самое. Это относится к умным указателям ('scoped_ptr' присутствует в boost, но отключен от стандарта), и потоки (некоторые детали в семантике операций были изменены с исходного boost :: thread ...) –

0

Как о том, что конструктор приватным и имеющий статический метод строительства, как это:

class MyClass : public IObserver 
    { 
    public: 
     static std::shared_ptr<MyClass> createObserver(std::shared_ptr<SomeOtherClass> otherClass); 
     void DoSomethingImportant(); 
    private: 
     MyClass (std::shared_ptr<SomeOtherClass> otherClass); 
     std::shared_ptr<SomeOtherClass> m_otherClass; 
    }; 

Тогда вы могли бы создать экземпляр наблюдателя чисто в статическом методе и не придется беспокоиться о этом указателе на всех.

+1

Предполагается, что наблюдатель (фактически: все наблюдатели) должен быть прикреплен во время строительства (что не всегда требуется). Также опечатка: вы, вероятно, намеревались сделать статический метод createObserver. – Patrick

0


Можете ли вы перевести стадию регистрации в отдельный метод? :

shared_ptr<SomeOtherClass> other(new SomeOtherClass()); 
shared_ptr<MyClass> my(new MyClass()); 
// register myself to the observer 
other->registerObserver(my); 
my->DoSomethingImportant(); 

Хороший дизайн шаблона наблюдателя может быть реализован с буст :: сигнала и повышение :: связать библиотеки. Я призываю вас взглянуть.

С наилучшими пожеланиями,
Marcin

3

Для шаблона наблюдателя, наблюдаемый объект не принимает права собственности наблюдателя, почему бы не просто использовать сырой указатель? Жизненный цикл наблюдателя должен контролироваться самим наблюдателем.

Используя enable_shared_from_this, вы вводите зависимость цикла для наблюдателя и его наблюдаемого объекта. Это означает, что если не удалять явно, ресурс никогда не будет выпущен.

Смежные вопросы