• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE HTML PUBLIC "-//SoftQuad Software//DTD HoTMetaL PRO 5.0::19981217::extensions to HTML 4.0//EN" "hmpro5.dtd">
2
3<HTML>
4
5<HEAD>
6<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
7<TITLE>In_place_factory Documentation</TITLE>
8</HEAD>
9
10<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#800080">
11<H2 align="left"><IMG SRC="../../boost.png" WIDTH="276" HEIGHT="86"></H2>
12
13<blockquote>
14  <blockquote>
15    <blockquote>
16      <blockquote>
17        <blockquote>
18          <blockquote>
19<H2 align="left">Header &lt;<A
20HREF="../../boost/utility/in_place_factory.hpp">boost/utility/in_place_factory.hpp</A>&gt; </H2>
21
22<H2 align="left">Header &lt;<A
23HREF="../../boost/utility/typed_in_place_factory.hpp">boost/utility/typed_in_place_factory.hpp</A>&gt; </H2>
24
25          </blockquote>
26        </blockquote>
27      </blockquote>
28    </blockquote>
29  </blockquote>
30</blockquote>
31<p>&nbsp;</p>
32
33<H2>Contents</H2>
34<DL CLASS="page-index">
35  <DT><A HREF="#mot">Motivation</A></DT>
36  <DT><A HREF="#framework">Framework</A></DT>
37  <DT><A HREF="#specification">Specification</A></DT>
38  <DT><A HREF="#container-usage">Container-side Usage</A></DT>
39  <DT><A HREF="#user-usage">User-side Usage</A></DT>
40</DL>
41
42<HR>
43
44<H2><A NAME="mot"></A>Motivation</H2>
45
46<p>Suppose we have a class</p>
47<pre>struct X
48{
49  X ( int, std::string ) ;
50} ;</pre>
51<p>And a container for it which supports an empty state (that is, which can contain zero objects):</p>
52<pre>struct C
53{
54   C() : contained_(0) {}
55  ~C() { delete contained_ ; }
56  X* contained_ ;
57} ;</pre>
58<p>A container designed to support an empty state typically doesn't require the contained type to be DefaultConstructible,
59but it typically requires it to be CopyConstructible as a mechanism to
60initialize the object to store:</p>
61<pre>struct C
62{
63   C() : contained_(0) {}
64   C ( X const& v ) : contained_ ( new X(v) ) {}
65  ~C() { delete contained_ ; }
66  X* contained_ ;
67} ;</pre>
68<p>There is a subtle problem with this: since the mechanism used to initialize the stored object is copy construction,
69there must exist a previously constructed source object to copy from. This
70object is likely to be temporary and serve no purpose besides being the source</p>
71<pre>void foo()
72{
73  // Temporary object created.
74  C c( X(123,"hello") ) ;
75}
76</pre>
77<p>A solution to this problem is to support direct construction of the contained
78object right in the container's storage.<br>
79In this scheme, the user supplies the arguments for the X constructor
80directly to the container:</p>
81<pre>struct C
82{
83   C() : contained_(0) {}
84   C ( X const& v ) : contained_ ( new X(v) ) {}
85   C ( int a0, std::string a1 ) : contained_ ( new X(a0,a1) ) {}
86  ~C() { delete contained_ ; }
87  X* contained_ ;
88} ;</pre>
89<pre>void foo()
90{
91  // Wrapped object constructed in-place
92  // No temporary created.
93  C c(123,"hello") ;
94}
95</pre>
96<p>Clearly, this solution doesn't scale well since the container must duplicate all the constructor overloads from the contained type
97(at least all those which are to be supported directly in the container).</p>
98
99<H2><A NAME="framework"></A>Framework</H2>
100<p>
101This library proposes a framework to allow some containers to directly contruct contained objects in-place without requiring
102the entire set of constructor overloads from the contained type. It also allows the container to remove the CopyConstuctible
103requirement from the contained type since objects can be directly constructed in-place without need of a copy.<br>
104The only requirement on the container is that it must provide proper storage (that is, correctly aligned and sized).
105Naturally, the container will typically support uninitialized storage to avoid the in-place construction to override
106a fully-constructed object (as this would defeat the purpose of in-place construction)
107</p>
108<p>For this purpose, the framework provides two families of classes collectively called: InPlaceFactories and TypedInPlaceFactories.<br>
109Essentially, these classes hold a sequence of actual parameters and a method to contruct an object in place using these parameters.
110Each member of the family differs only in the number (and type) of the parameter list. The first family
111takes the type of the object to construct directly in method provided for that
112purpose, whereas the second family incorporates that type in the factory class
113itself..</p>
114<p>From the container POV, using the framework amounts to calling the factory's method to contruct the object in place.
115From the user POV, it amounts to creating the right factory object to hold the parameters and pass it to the container.<br>
116The following simplified example shows the basic idea. A complete example follows the formal specification of the framework:</p>
117<pre>struct C
118{
119   template&lt;class InPlaceFactory&gt;
120   C ( InPlaceFactory const& aFactory )
121    :
122    contained_ ( uninitialized_storage() )
123   {
124     aFactory.template apply&lt;X&gt;(contained_);
125   }
126
127  ~C()
128  {
129    contained_ -> X::~X();
130    delete[] contained_ ;
131  }
132
133  char* uninitialized_storage() { return new char[sizeof(X)] ; }
134
135  char* contained_ ;
136} ;
137
138void foo()
139{
140  C c( in_place(123,"hello") ) ;
141}
142</pre>
143
144<HR>
145
146<H2><A NAME="specification">Specification</A></H2>
147
148<p>The following is the first member of the family of 'in_place_factory' classes, along with its corresponding helper template function.
149The rest of the family varies only in the number and type of template (and constructor) parameters.</p>
150<PRE>namespace boost {
151
152struct in_place_factory_base {} ;
153
154template&lt;class A0&gt;
155class in_place_factory : public in_place_factory_base
156{
157  public:</PRE>
158
159<PRE>    in_place_factory ( A0 const& a0 ) : m_a0(a0) {}
160
161    template&lt; class T &gt;
162    void apply ( void* address ) const
163    {
164      new (address) T(m_a0);
165    }
166
167  private:</PRE>
168
169<PRE>    A0 const& m_a0 ;
170} ;
171
172template&lt;class A0&gt;
173in_place_factory&lt;A0&gt; in_place ( A0 const& a0 )
174{
175  return in_place_factory&lt;A0&gt;(a0);
176}
177</PRE>
178
179<p>Similarly, the following is the first member of the family of 'typed_in_place_factory' classes, along with its corresponding
180helper template function. The rest of the family varies only in the number and type of template (and constructor) parameters.</p>
181<PRE>namespace boost {
182
183struct typed_in_place_factory_base {} ;
184
185template&lt;class T, class A0&gt;
186class typed_in_place_factory : public typed_in_place_factory_base
187{
188  public:</PRE>
189
190<PRE>    typed_in_place_factory ( A0 const& a0 ) : m_a0(a0) {}
191
192    void apply ( void* address ) const
193    {
194      new (address) T(m_a0);
195    }
196
197  private:</PRE>
198
199<PRE>    A0 const& m_a0 ;
200} ;
201
202template&lt;class T, class A0&gt;
203typed_in_place_factory&lt;A0&gt; in_place ( A0 const& a0 )
204{
205  return typed_in_place_factory&lt;T,A0&gt;(a0);
206}</PRE>
207
208<PRE>}
209</PRE>
210
211<p>As you can see, the 'in_place_factory' and 'typed_in_place_factory' template classes varies only in the way they specify
212the target type: in the first family, the type is given as a template argument to the apply member function while in the
213second it is given directly as part of the factory class.<br>
214When the container holds a unique non-polymorphic type (such as the case of Boost.Optional), it knows the exact dynamic-type
215of the contained object and can pass it to the apply() method of a (non-typed) factory.
216In this case, end users can use an 'in_place_factory' instance which can be constructed without the type of the object to construct.<br>
217However, if the container holds heterogeneous or polymorphic objects (such as the case of Boost.Variant), the dynamic-type
218of the object to be constructed must be known by the factory itslef. In this case, end users must use a 'typed_in_place_factory'
219instead.</p>
220
221<HR>
222
223<h2><A NAME="container-usage">Container-side Usage</a></h2>
224
225<p>As shown in the introductory simplified example, the container class must
226contain methods that accept an instance of
227these factories and pass the object's storage to the factory's apply method.<br>
228However, the type of the factory class cannot be completly specified in the container class because that would
229defeat the whole purpose of the factories which is to allow the container to accept a variadic argument list
230for the constructor of its contained object.<br>
231The correct function overload must be based on the only distinctive and common
232characteristic of all the classes in each family, the base class.<br>
233Depending on the container class, you can use 'enable_if' to generate the right overload, or use the following
234dispatch technique (used in the Boost.Optional class):
235</p>
236<pre>struct C
237{
238   C() : contained_(0) {}
239   C ( X const& v ) : contained_ ( new X(v) ) {}
240
241   template&lt;class Expr&gt
242   C ( Expr const& expr )
243    :
244    contained_ ( uninitialized_storage() )
245   {
246    construct(expr,&expr)
247   }
248
249  ~C() { delete contained_ ; }
250
251  template&lt;class InPlaceFactory&gt;
252  void construct ( InPlaceFactory const& aFactory, boost::in_place_factory_base* )
253  {
254    aFactory.template apply&lt;X&gt;(contained_);
255  }
256
257  template&lt;class TypedInPlaceFactory&gt;
258  void construct ( TypedInPlaceFactory const& aFactory, boost::typed_in_place_factory_base* )
259  {
260    aFactory.apply(contained_);
261  }
262
263  X* uninitialized_storage() { return static_cast&lt;X*&gt;(new char[sizeof(X)]) ; }
264
265  X* contained_ ;
266} ;
267</pre>
268
269<hr>
270
271<h2><A NAME="user-usage">User-side Usage</a></h2>
272
273<p>End users pass to the container an instance of a factory object holding the actual parameters needed to construct the
274contained object directly within the container. For this, the helper template function 'in_place' is used.<br>
275The call 'in_place(a0,a1,a2,...,an)' constructs a (non-typed) 'in_place_factory' instance with the given argument list.<br>
276The call 'in_place&lt;T&gt;(a0,a1,a2,...,an)' constructs a 'typed_in_place_factory' instance with the given argument list for the
277type 'T'.</p>
278<pre>void foo()
279{
280  C a( in_place(123,"hello") ) ;    // in_place_factory passed
281  C b( in_place&lt;X&gt;(456,"world") ) ; // typed_in_place_factory passed
282}
283</pre>
284
285<P>Revised September 17, 2004</P>
286<p>� Copyright Fernando Luis Cacciola Carballal, 2004</p>
287<p> Use, modification, and distribution are subject to the Boost Software
288License, Version 1.0. (See accompanying file <a href="../../LICENSE_1_0.txt">
289LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
290www.boost.org/LICENSE_1_0.txt</a>)</p>
291<P>Developed by <A HREF="mailto:fernando_cacciola@hotmail.com">Fernando Cacciola</A>,
292the latest version of this file can be found at <A
293HREF="http://www.boost.org">www.boost.org</A>, and the boost
294<A HREF="http://www.boost.org/more/mailing_lists.htm#main">discussion lists</A></P>
295</BODY>
296</HTML>
297