Question

I'm working on C++ framework and would like to apply automatic memory management to a number of core classes. So far, I have the standard approach which is

class Foo 
{

public:

  static
  shared_ptr<Foo> init() 
  {
    return shared_ptr<Foo>(new Foo);
  }

  ~Foo() 
  {
  }

protected:

  Foo()
  {
  }

};


// Example of use
shared_ptr<Foo> f = Foo::init();

However, the above breaks when I subclass Foo, since even tho init() is inherited, it still returns shared_ptr<Foo> which contains a pointer to instance of Foo.

Can anyone think of an elegant solution to this? Should I perhaps just stick with (semi-)manually wrapping instances of class with shared_ptr? This would also give ability to expose parameterized constructors without declaring new named constructors...

Ie.

template <typename T>
shared_ptr<T> make_shared(T* ptr)
{
  return shared_ptr<T>(ptr)
}

// Example
shared_ptr<T> 
  f1 = make_shared(new Foo()),
  f2 = make_shared(new Foo(1,2));
Was it helpful?

Solution

I don't understand what this achieves, you don't appear to be getting any extra memory management using this init function than by simply declaring a shared_ptr.

int main( void )
{
    shared_ptr<foo> a = foo::init();
    shared_ptr<foo> b( new foo );
}

What's the difference. shared_ptr provides the memory management, not anything in init.

OTHER TIPS

I would try something like this:

template<class T>
class creator
{
  public:
    static shared_ptr<T> init()
    {
      return(shared_ptr<T>(new T));
    }
};

class A : public creator<A>
{
};

class B : public A, public creator<B>
{
  public:
    using make_shared<B>::init;
};

// example use
shared_ptr<A> a = A::init();
shared_ptr<B> b = B::init();

But this isn't necessarily saving you a thing compared to standalone template you proposed.

Edit: I missed previous answer, this seems to be the same idea.

It seems that the goal is to make it impossible for users of the classes to call the constructors directly, and only expose a routine which returns shared_ptr's.

But if you want to apply this pattern, you need to replicate it in all the subclasses. The subclasses cannot automatically "inherit" init() so that init() would still call the subclass constructor, because init() is not a virtual method and is called without an object.

I would leave the constructors exposed as usual and just use the standard

shared_ptr<X> x = new X();

This keeps cognitive burden low, is readable, and remains flexible. This is how we program in our company with reference counted objects, anyway.

How about...

template<typename Derived>
class Foo 
{
public:

    static shared_ptr<Derived> init() 
    {
        return shared_ptr<Derived>(new Derived);
    }

    ~Foo() 
    {
    }

protected:

    Foo()
    {
    }

};


class Bar : public Foo<Bar>
{
};

int _tmain(int argc, _TCHAR* argv[])
{
    shared_ptr<Bar> b = Foo<Bar>::init(); 
    return 0;
}

Why not introduce a common base with a virtual destructor, inherit all necessary classes from it and simply use new?

It's generally not a good idea to force creation of objects using shared_ptr by hiding the constructors. I'm speaking from personal experience here working with an internal company lib that did exactly that. If you want to ensure people always wrap their allocated objects, just make sure that all arguments and members which store instances of these types expect a shared_ptr or weak_ptr instead of a naked pointer or reference. You might also want to derive these classes from enable_shared_from_this, because in a system where all objects are shared, at some point you'll have to pass the this pointer to one of these other objects' methods, and since they're designed only to accept shared_ptr, you're in pretty bad shape if your object has no internal_weak_this to ensure it isn't destroyed.

You need the static factory function in every type of the entire hierarchy.

class Foo
{
public:
    static shared_ptr< Foo > instantiate( /* potential arguments */ )
    {
           return shared_ptr< Foo >( new Foo( /* potential arguments */ );
    }

// blah blah blah
};

class Bar : public Foo
{
public:
    static shared_ptr< Bar > instantiate( /* potential arguments */ )
    {
           return shared_ptr< Bar >( new Bar( /* potential arguments */ );
    }

// blah blah blah
};

If you still have any confusion, please search CppCodeProvider on sourceforge and see how its done there.

By the way, in large C++ frameworks it's common to hide the "automatic memory management" from the coder. This lets him write shorter and simpler code. For example, in Qt you can do this:

QPixmap foo() {
    QPixmap pixmap(10, 10);
    return pixmap;
}

void bar() {
    QPixmap a = foo(); // no copying occurs, internal refcount incremented.
    QPixmap b = a;     // ditto.
    QPainter p(&b);
    p.drawPoint(5, 5); // data can no longer be shared, so a copy is made.
    // at this point 'a' is still unchanged!
    p.end();
}

Like many things in Qt, this mimics the Java object model, but it goes further by implementing copy-on-write (which it calls implicit sharing). This is intended to make the API behavior less suprising to C++ coders, who aren't used to having to call clone().

This is implemented via the d-pointer idiom, which kills two birds with one stone - you provide automatic memory management, and you insulate your implementation from the user (pimpl).

You can look at the actual implementation of QPixmap here: qpixmap.cpp, qpixmap.h.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top