Class factories and shared_ptr<T>
One way to control object memory and initialization is to wrap object creation in a class factory. This is the point of the proposed make_shared<T>(..) and allocate_shared<T>(..) standard library functions.
But it is easy to roll your own simple factory function:
# include <boost/shared_ptr.hpp>
using boost::shared_ptr;
class
factory_type
{
/* this_type type alias */
private:
typedef
factory_type
this_type;
// ======== Disable Copy ============
/* disabled copy ctor */
private:
factory_type( this_type const &)
; /* no implementation */
/* disabled copy assignment */
private:
void
operator =( this_type const &)
; /* no implementation */
// ======== Factory =================
/* private default ctor */
private:
factory_type( )
{ }
/* public (unfortunately) dtor */
public:
~factory_type( )
{ }
/* factory, only way to make these objects */
public:
static
shared_ptr< this_type >
make_new( )
{ return
shared_ptr< this_type >(
new this_type);
}
};
shared_ptr< factory_type >
factory_inst(
factory_type::make_new( ));
And there you have factor_type, a tightly controlled class where all insts are created in the factory (factory_type::make_new( )) and all deletes are through shared_ptr<T>s. The private constructors means not only can we not “new” the class ourselves, we also cannot use it as a supertype. Nor can we declare a factory_type class member or stack variable.
factor_type would be improved, however, if we could ensure that only shared_ptr<T>s could access the destructor. It doesn’t work to declare the destructor private and friend class shared_ptr< this_type > because the destructor is actually called from a deleter function. However we can friend the deleter function:
class
factory_type
{
... as above ...
/* private dtor */
private:
~factory_type( )
{ }
/* the only function that calls the dtor */
friend void boost::checked_delete( this_type *);
/* factory, only way to make these objects */
public:
static
shared_ptr< this_type >
make_new( )
{ return
shared_ptr< this_type >(
new this_type);
}
};
This works fine, but you get the following warning from msvc++9.0: the inline specifier cannot be used when a friend declaration refers to a specialization of a function template. Of course you can disable this warning. It’s not very important and likely to go away in a future version of msvc++ anyway, and it may even be corrected by an optimized non-debug compile.
The nicest solution, however, is to provide a private non-templated deleter. It doesn’t issue the above warning and it feels more portable. It’s only drawback is that it slightly increases the size of the intermediate ref-count object.
class
factory_type
{
... as above ...
/* private dtor */
private:
~factory_type( )
{ }
/* the only place where the dtor is used */
private:
struct
private_deleter
{ void
operator ()( this_type * p)
{ delete p; }
};
/* factory, only way to make these objects */
public:
static
shared_ptr< this_type >
make_new( )
{ return
shared_ptr< this_type >(
new this_type,
private_deleter( ));
}
};
Comments
Leave a Reply