f0c62e9e00
[SVN r82729]
297 lines
10 KiB
HTML
297 lines
10 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//SoftQuad Software//DTD HoTMetaL PRO 5.0::19981217::extensions to HTML 4.0//EN" "hmpro5.dtd">
|
||
|
||
<HTML>
|
||
|
||
<HEAD>
|
||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||
<TITLE>In_place_factory Documentation</TITLE>
|
||
</HEAD>
|
||
|
||
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#800080">
|
||
<H2 align="left"><IMG SRC="../../boost.png" WIDTH="276" HEIGHT="86"></H2>
|
||
|
||
<blockquote>
|
||
<blockquote>
|
||
<blockquote>
|
||
<blockquote>
|
||
<blockquote>
|
||
<blockquote>
|
||
<H2 align="left">Header <<A
|
||
HREF="../../boost/utility/in_place_factory.hpp">boost/utility/in_place_factory.hpp</A>> </H2>
|
||
|
||
<H2 align="left">Header <<A
|
||
HREF="../../boost/utility/typed_in_place_factory.hpp">boost/utility/typed_in_place_factory.hpp</A>> </H2>
|
||
|
||
</blockquote>
|
||
</blockquote>
|
||
</blockquote>
|
||
</blockquote>
|
||
</blockquote>
|
||
</blockquote>
|
||
<p> </p>
|
||
|
||
<H2>Contents</H2>
|
||
<DL CLASS="page-index">
|
||
<DT><A HREF="#mot">Motivation</A></DT>
|
||
<DT><A HREF="#framework">Framework</A></DT>
|
||
<DT><A HREF="#specification">Specification</A></DT>
|
||
<DT><A HREF="#container-usage">Container-side Usage</A></DT>
|
||
<DT><A HREF="#user-usage">User-side Usage</A></DT>
|
||
</DL>
|
||
|
||
<HR>
|
||
|
||
<H2><A NAME="mot"></A>Motivation</H2>
|
||
|
||
<p>Suppose we have a class</p>
|
||
<pre>struct X
|
||
{
|
||
X ( int, std::string ) ;
|
||
} ;</pre>
|
||
<p>And a container for it which supports an empty state (that is, which can contain zero objects):</p>
|
||
<pre>struct C
|
||
{
|
||
C() : contained_(0) {}
|
||
~C() { delete contained_ ; }
|
||
X* contained_ ;
|
||
} ;</pre>
|
||
<p>A container designed to support an empty state typically doesn't require the contained type to be DefaultConstructible,
|
||
but it typically requires it to be CopyConstructible as a mechanism to
|
||
initialize the object to store:</p>
|
||
<pre>struct C
|
||
{
|
||
C() : contained_(0) {}
|
||
C ( X const& v ) : contained_ ( new X(v) ) {}
|
||
~C() { delete contained_ ; }
|
||
X* contained_ ;
|
||
} ;</pre>
|
||
<p>There is a subtle problem with this: since the mechanism used to initialize the stored object is copy construction,
|
||
there must exist a previously constructed source object to copy from. This
|
||
object is likely to be temporary and serve no purpose besides being the source</p>
|
||
<pre>void foo()
|
||
{
|
||
// Temporary object created.
|
||
C c( X(123,"hello") ) ;
|
||
}
|
||
</pre>
|
||
<p>A solution to this problem is to support direct construction of the contained
|
||
object right in the container's storage.<br>
|
||
In this scheme, the user supplies the arguments for the X constructor
|
||
directly to the container:</p>
|
||
<pre>struct C
|
||
{
|
||
C() : contained_(0) {}
|
||
C ( X const& v ) : contained_ ( new X(v) ) {}
|
||
C ( int a0, std::string a1 ) : contained_ ( new X(a0,a1) ) {}
|
||
~C() { delete contained_ ; }
|
||
X* contained_ ;
|
||
} ;</pre>
|
||
<pre>void foo()
|
||
{
|
||
// Wrapped object constructed in-place
|
||
// No temporary created.
|
||
C c(123,"hello") ;
|
||
}
|
||
</pre>
|
||
<p>Clearly, this solution doesn't scale well since the container must duplicate all the constructor overloads from the contained type
|
||
(at least all those which are to be supported directly in the container).</p>
|
||
|
||
<H2><A NAME="framework"></A>Framework</H2>
|
||
<p>
|
||
This library proposes a framework to allow some containers to directly contruct contained objects in-place without requiring
|
||
the entire set of constructor overloads from the contained type. It also allows the container to remove the CopyConstuctible
|
||
requirement from the contained type since objects can be directly constructed in-place without need of a copy.<br>
|
||
The only requirement on the container is that it must provide proper storage (that is, correctly aligned and sized).
|
||
Naturally, the container will typically support uninitialized storage to avoid the in-place construction to override
|
||
a fully-constructed object (as this would defeat the purpose of in-place construction)
|
||
</p>
|
||
<p>For this purpose, the framework provides two families of classes collectively called: InPlaceFactories and TypedInPlaceFactories.<br>
|
||
Essentially, these classes hold a sequence of actual parameters and a method to contruct an object in place using these parameters.
|
||
Each member of the family differs only in the number (and type) of the parameter list. The first family
|
||
takes the type of the object to construct directly in method provided for that
|
||
purpose, whereas the second family incorporates that type in the factory class
|
||
itself..</p>
|
||
<p>From the container POV, using the framework amounts to calling the factory's method to contruct the object in place.
|
||
From the user POV, it amounts to creating the right factory object to hold the parameters and pass it to the container.<br>
|
||
The following simplified example shows the basic idea. A complete example follows the formal specification of the framework:</p>
|
||
<pre>struct C
|
||
{
|
||
template<class InPlaceFactory>
|
||
C ( InPlaceFactory const& aFactory )
|
||
:
|
||
contained_ ( uninitialized_storage() )
|
||
{
|
||
aFactory.template apply<X>(contained_);
|
||
}
|
||
|
||
~C()
|
||
{
|
||
contained_ -> X::~X();
|
||
delete[] contained_ ;
|
||
}
|
||
|
||
char* uninitialized_storage() { return new char[sizeof(X)] ; }
|
||
|
||
char* contained_ ;
|
||
} ;
|
||
|
||
void foo()
|
||
{
|
||
C c( in_place(123,"hello") ) ;
|
||
}
|
||
</pre>
|
||
|
||
<HR>
|
||
|
||
<H2><A NAME="specification">Specification</A></H2>
|
||
|
||
<p>The following is the first member of the family of 'in_place_factory' classes, along with its corresponding helper template function.
|
||
The rest of the family varies only in the number and type of template (and constructor) parameters.</p>
|
||
<PRE>namespace boost {
|
||
|
||
struct in_place_factory_base {} ;
|
||
|
||
template<class A0>
|
||
class in_place_factory : public in_place_factory_base
|
||
{
|
||
public:</PRE>
|
||
|
||
<PRE> in_place_factory ( A0 const& a0 ) : m_a0(a0) {}
|
||
|
||
template< class T >
|
||
void apply ( void* address ) const
|
||
{
|
||
new (address) T(m_a0);
|
||
}
|
||
|
||
private:</PRE>
|
||
|
||
<PRE> A0 const& m_a0 ;
|
||
} ;
|
||
|
||
template<class A0>
|
||
in_place_factory<A0> in_place ( A0 const& a0 )
|
||
{
|
||
return in_place_factory<A0>(a0);
|
||
}
|
||
</PRE>
|
||
|
||
<p>Similarly, the following is the first member of the family of 'typed_in_place_factory' classes, along with its corresponding
|
||
helper template function. The rest of the family varies only in the number and type of template (and constructor) parameters.</p>
|
||
<PRE>namespace boost {
|
||
|
||
struct typed_in_place_factory_base {} ;
|
||
|
||
template<class T, class A0>
|
||
class typed_in_place_factory : public typed_in_place_factory_base
|
||
{
|
||
public:</PRE>
|
||
|
||
<PRE> typed_in_place_factory ( A0 const& a0 ) : m_a0(a0) {}
|
||
|
||
void apply ( void* address ) const
|
||
{
|
||
new (address) T(m_a0);
|
||
}
|
||
|
||
private:</PRE>
|
||
|
||
<PRE> A0 const& m_a0 ;
|
||
} ;
|
||
|
||
template<class T, class A0>
|
||
typed_in_place_factory<A0> in_place ( A0 const& a0 )
|
||
{
|
||
return typed_in_place_factory<T,A0>(a0);
|
||
}</PRE>
|
||
|
||
<PRE>}
|
||
</PRE>
|
||
|
||
<p>As you can see, the 'in_place_factory' and 'typed_in_place_factory' template classes varies only in the way they specify
|
||
the target type: in the first family, the type is given as a template argument to the apply member function while in the
|
||
second it is given directly as part of the factory class.<br>
|
||
When the container holds a unique non-polymorphic type (such as the case of Boost.Optional), it knows the exact dynamic-type
|
||
of the contained object and can pass it to the apply() method of a (non-typed) factory.
|
||
In this case, end users can use an 'in_place_factory' instance which can be constructed without the type of the object to construct.<br>
|
||
However, if the container holds heterogeneous or polymorphic objects (such as the case of Boost.Variant), the dynamic-type
|
||
of the object to be constructed must be known by the factory itslef. In this case, end users must use a 'typed_in_place_factory'
|
||
instead.</p>
|
||
|
||
<HR>
|
||
|
||
<h2><A NAME="container-usage">Container-side Usage</a></h2>
|
||
|
||
<p>As shown in the introductory simplified example, the container class must
|
||
contain methods that accept an instance of
|
||
these factories and pass the object's storage to the factory's apply method.<br>
|
||
However, the type of the factory class cannot be completly specified in the container class because that would
|
||
defeat the whole purpose of the factories which is to allow the container to accept a variadic argument list
|
||
for the constructor of its contained object.<br>
|
||
The correct function overload must be based on the only distinctive and common
|
||
characteristic of all the classes in each family, the base class.<br>
|
||
Depending on the container class, you can use 'enable_if' to generate the right overload, or use the following
|
||
dispatch technique (used in the Boost.Optional class):
|
||
</p>
|
||
<pre>struct C
|
||
{
|
||
C() : contained_(0) {}
|
||
C ( X const& v ) : contained_ ( new X(v) ) {}
|
||
|
||
template<class Expr>
|
||
C ( Expr const& expr )
|
||
:
|
||
contained_ ( uninitialized_storage() )
|
||
{
|
||
construct(expr,&expr)
|
||
}
|
||
|
||
~C() { delete contained_ ; }
|
||
|
||
template<class InPlaceFactory>
|
||
void construct ( InPlaceFactory const& aFactory, boost::in_place_factory_base* )
|
||
{
|
||
aFactory.template apply<X>(contained_);
|
||
}
|
||
|
||
template<class TypedInPlaceFactory>
|
||
void construct ( TypedInPlaceFactory const& aFactory, boost::typed_in_place_factory_base* )
|
||
{
|
||
aFactory.apply(contained_);
|
||
}
|
||
|
||
X* uninitialized_storage() { return static_cast<X*>(new char[sizeof(X)]) ; }
|
||
|
||
X* contained_ ;
|
||
} ;
|
||
</pre>
|
||
|
||
<hr>
|
||
|
||
<h2><A NAME="user-usage">User-side Usage</a></h2>
|
||
|
||
<p>End users pass to the container an instance of a factory object holding the actual parameters needed to construct the
|
||
contained object directly within the container. For this, the helper template function 'in_place' is used.<br>
|
||
The call 'in_place(a0,a1,a2,...,an)' constructs a (non-typed) 'in_place_factory' instance with the given argument list.<br>
|
||
The call 'in_place<T>(a0,a1,a2,...,an)' constructs a 'typed_in_place_factory' instance with the given argument list for the
|
||
type 'T'.</p>
|
||
<pre>void foo()
|
||
{
|
||
C a( in_place(123,"hello") ) ; // in_place_factory passed
|
||
C b( in_place<X>(456,"world") ) ; // typed_in_place_factory passed
|
||
}
|
||
</pre>
|
||
|
||
<P>Revised September 17, 2004</P>
|
||
<p><EFBFBD> Copyright Fernando Luis Cacciola Carballal, 2004</p>
|
||
<p> Use, modification, and distribution are subject to the Boost Software
|
||
License, Version 1.0. (See accompanying file <a href="../../LICENSE_1_0.txt">
|
||
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
||
www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||
<P>Developed by <A HREF="mailto:fernando_cacciola@hotmail.com">Fernando Cacciola</A>,
|
||
the latest version of this file can be found at <A
|
||
HREF="http://www.boost.org">www.boost.org</A>, and the boost
|
||
<A HREF="http://www.boost.org/more/mailing_lists.htm#main">discussion lists</A></P>
|
||
</BODY>
|
||
</HTML>
|