Шаблон интерфейса с shared_ptr - PullRequest
1 голос
/ 14 июля 2011

Я хочу иметь следующую структуру классов:

#include <tr1/memory>

class Interface;
class Impl;

class Impl
{
public:
    Impl( std::tr1::weak_ptr< Interface > interface );

private:
    std::tr1::weak_ptr< Interface > interface_;
};

class Interface
{
public:
    Interface() { impl_ = new Impl( this ); }

private:
    std::tr1::shared_ptr< Impl > impl_;
};

Impl::Impl( std::tr1::weak_ptr< Interface > interface )
        : interface_(interface)
{}

Код не работает, так как weak_ptr может быть создан только из shared_ptr.Я не могу создать shared_ptr этого в ctor, так как он разрушит объект при выходе из ctor.

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

Есть ли элегантный способ установить эти отношения?

Ответы [ 2 ]

0 голосов
/ 14 июля 2011

Я решил это, убрав необходимость использовать shared_ptr из Impl.

Основной проблемой было то, что Интерфейс является Узлом в ориентированном ациклическом графе.Каждый узел знает своих родителей и потомков, поэтому реализация Node :: addChild (shared_ptr child) невозможна, поскольку узел не может быть добавлен как parent_ptr к дочерним родителям.

Одним из способов является использованиеintrusive_ptr, но я решил это с помощью статического метода Node :: link (shared_ptr parent, shared_ptr child) на данный момент.

Я мог бы в конечном итоге использовать intrusive_ptr, если мне понадобитсяenable_shared_from_this-like операция.

0 голосов
/ 14 июля 2011

Если я правильно понял ваш вопрос, я думаю, вы можете использовать std :: tr1 :: enable_shared_from_this для достижения желаемого эффекта:

#include <tr1/memory>

class Interface;
class Impl;

class Impl
{
public:
    Impl( const std::tr1::weak_ptr< Interface >& interface );

private:
    const std::tr1::weak_ptr< Interface > interface_;
};

class Interface : public std::tr1::enable_shared_from_this<Interface>
{
public:
    Interface();
    std::tr1::shared_ptr< Impl > getImpl();

private:
    std::tr1::shared_ptr< Impl > impl_;
};

inline Interface::Interface()
{
}
std::tr1::shared_ptr< Impl > Interface::getImpl()
{
    if ( !impl_ ) {
        impl_ = std::tr1::shared_ptr< Impl >( new Impl( shared_from_this() ) );
    }
    return impl_;
}

inline Impl::Impl( const std::tr1::weak_ptr< Interface >& interface )
        : interface_(interface)
{}


int main(int argc, char* argv[])
{
    std::tr1::shared_ptr< Interface >  x(new Interface());
    return 0;
}

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

...