123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- <!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>© 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>
|