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