开发者

Interface pattern with shared_ptr

开发者 https://www.devze.com 2023-03-20 02:25 出处:网络
I want to have the following class structure: #include <tr1/memory> class Interface; class Impl; class Impl

I want to have the following class structure:

#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 ); }

p开发者_JS百科rivate:
    std::tr1::shared_ptr< Impl > impl_;
};

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

The code doesn't work since a weak_ptr can only be constructed from a shared_ptr. I can't construct a shared_ptr of this in the ctor since it would destroy the object when leaving the ctor.

The interface will be held as a shared_ptr by the caller. The Implementation needs to be shared_ptr since its lifetime is longer than the Interface lifetime.

Is there an elegant way to establish this relationship?


I solved it by removing the need to use shared_ptr< Interface > from the Impl.

The underlying problem was that the Interface is a Node in a directed acyclic graph. Each node knows its parents and children, so implementing a Node::addChild( shared_ptr< Node > child ) is impossible, since the node cannot be added as a weak_ptr to the child's parents.

One way is to use intrusive_ptr, but I solved it by using a static Node::link( shared_ptr< Node > parent, shared_ptr< Node > child ) method for now.

I might end up using intrusive_ptr later if I need to do a enable_shared_from_this-like operation.


If I've understood your question correctly, I think you can use std::tr1::enable_shared_from_this to achieve the effect you want:

#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;
}

The relationship may not be very nice (as judging by the class names), but the general problem of creating circular structures with smart pointers is valid. The shared pointer to the Interface instance must have have been created before shared_from_this() is called. This means that Interface must be allocated dynamically and handled by a smart pointer, and that shared_from_this() cannot be called from the Interface constructor, so I have added the lazy getter to create the Impl instance.

0

精彩评论

暂无评论...
验证码 换一张
取 消