ContentsMotivationSuppose 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. 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. For this purpose, the framework provides two families of classes collectively called: InPlaceFactories and TypedInPlaceFactories. 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. struct C { template<class InPlaceFactory> C ( InPlaceFactory const& aFactoty ) : 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") ) ; } SpecificationThe 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. Container-side UsageAs 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. 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 UsageEnd 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. 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 Fernando Luis Cacciola Carballal, 2004 Use, modification, and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at www.boost.org/LICENSE_1_0.txt) Developed by Fernando Cacciola, the latest version of this file can be found at www.boost.org, and the boost discussion lists |