diff --git a/in_place_factories.html b/in_place_factories.html new file mode 100644 index 0000000..d5503c9 --- /dev/null +++ b/in_place_factories.html @@ -0,0 +1,295 @@ + + + + + + + +Header + + + +

+ +
+
+
+
+
+
+

Header <boost/utility/in_place_factory.hpp>

+ +

Header <boost/utility/typed_in_place_factory.hpp>

+ +
+
+
+
+
+
+

 

+ +

Contents

+
+
Motivation
+
Framework
+
Specification
+
Container-side Usage
+
User-side Usage
+
+ +
+ +

Motivation

+ +

Suppose we have a class

+
struct X 
+{
+  X ( int, std:::string ) ; 
+} ;
+

And a container for it which supports an empty state (that is, which can contain zero objects):

+
struct C
+{
+   C() : contained_(0) {}
+  ~C() { delete contained_ ; }
+  X* contained_ ;
+} ;
+

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:

+
struct C
+{
+   C() : contained_(0) {}
+   C ( X const& v ) : contained_ ( new X(v) ) {}
+  ~C() { delete contained_ ; }
+  X* contained_ ;
+} ;
+

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

+
void foo()
+{
+  // Temporary object created.
+  C c( X(123,"hello") ) ; 
+}
+
+

A solution to this problem is to support direct construction of the contained +object right in the container's storage.
+In this shceme, the user supplies the arguments for the X constructor +directly to the container:

+
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_ ;
+} ;
+
void foo()
+{
+  // Wrapped object constructed in-place
+  // No temporary created.
+  C c(123,"hello") ; 
+}
+
+

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).

+ +

Framework

+

+This library proposes a framework to allow some containers to directly contruct contained objects in-place without requiring +the entire set of constructor overloads ftom 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.
+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) +

+

For this purpose, the framework provides two families of classes collectively called: InPlaceFactories and TypedInPlaceFactories.
+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..

+

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.
+The following simplified example shows the basic idea. A complete example follows the formal specification of the framework:

+
struct C
+{
+   C() : contained_(0) {}
+   C ( X const& v ) : contained_ ( new X(v) ) {}
+   
+   template<class InPlaceFactory> 
+   C ( InPlaceFactory const& aFactoty )
+    : 
+    contained_ ( uninitialized_storage() ) 
+   {
+     aFactory.template apply<X>(contained_);
+   }
+   
+  ~C() { delete contained_ ; }
+  
+  X* uninitialized_storage() { return static_cast<X*>(new char[sizeof(X)]) ; }
+  
+  X* contained_ ;
+} ;
+
+void foo()
+{
+  C c( in_place(123,"hello" ) ;
+}
+
+ +
+ +

Specification

+ +

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.

+
namespace boost {
+
+struct in_place_factory_base {} ;
+
+template<class A0>
+class in_place_factory : public in_place_factory_base
+{
+  public:
+ +
    in_place_factory ( A0 const& a0 ) : m_a0(a0) {}
+  
+    template< class T >
+    void apply ( void* address ) const
+    {
+      new (address) T(m_a0);
+    }
+  
+  private:
+ +
    A0 const& m_a0 ;
+} ;
+
+template<class A0>
+in_place_factory<A0> in_place ( A0 const& a0 )
+{
+  return in_place_factory<A0>(a0);
+}
+
+ +

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.

+
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:
+ +
    typed_in_place_factory ( A0 const& a0 ) : m_a0(a0) {}
+  
+    void apply ( void* address ) const
+    {
+      new (address) T(m_a0);
+    }
+  
+  private:
+ +
    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);
+}
+ +
}
+
+ +

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.
+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.
+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.

+ +
+ +

Container-side Usage

+ +

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.
+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.
+The correct function overload must be based on the only distinctive and common +characteristic of all the classes in each family, the base class.
+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): +

+
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_ ;
+} ;
+
+ +
+ +

User-side Usage

+ +

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.
+The call 'in_place(a0,a1,a2,...,an)' constructs a (non-typed) 'in_place_factory' instance with the given argument list.
+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'.

+
void foo()
+{
+  C a( in_place(123,"hello") ) ;    // in_place_factory passed
+  C b( in_place<X>(456,"world") ) ; // typed_in_place_factory passed
+}
+
+ +

Revised September 17, 2004

+

© Copyright boost.org 2004. Permission to copy, use, modify, sell and + distribute this document is granted provided this copyright notice appears in + all copies. This document is provided "as is" without express or implied + warranty, and with no claim as to its suitability for any purpose.

+

Developed by Fernando Cacciola, +the latest version of this file can be found at www.boost.org, and the boost +discussion lists

+ + \ No newline at end of file