Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

In_place_factory Documentation

Boost , ,

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

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

Предположим, что у нас есть класс

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

И контейнер для него, который поддерживает пустое состояние (то есть может содержать нулевые объекты):

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

Контейнер, предназначенный для поддержки пустого состояния, обычно не требует, чтобы содержащийся тип был конструктивным по умолчанию, но обычно требует, чтобы он был совместимым с копией в качестве механизма инициализации объекта для хранения:

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

Существует тонкая проблема с этим: поскольку механизм, используемый для инициализации хранимого объекта, представляет собой конструкцию копии, должен существовать ранее построенный объект-источник для копирования. Этот объект, вероятно, будет временным и не будет служить никакой цели, кроме как быть источником.

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

Решение этой проблемы заключается в поддержке непосредственного строительства содержащегося объекта прямо в контейнере.
В этой схеме пользователь поставляет аргументы для конструктора X непосредственно в контейнер:

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") ;
}

Очевидно, что это решение плохо масштабируется, поскольку контейнер должен дублировать все перегрузки конструктора из содержащегося типа (по крайней мере, все те, которые должны поддерживаться непосредственно в контейнере).

Framework

Эта библиотека предлагает структуру, позволяющую некоторым контейнерам напрямую конструировать содержащиеся объекты на месте, не требуя полного набора перегрузок конструктора от содержащегося типа. Он также позволяет контейнеру удалять требование CopyConstuctible из содержащегося типа, поскольку объекты могут быть непосредственно построены на месте без необходимости копирования.
Единственным требованием к контейнеру является то, что он должен обеспечивать надлежащее хранение (то есть правильно выровненный и размерный). Естественно, контейнер, как правило, поддерживает неинициализированное хранение, чтобы избежать строительства на месте, чтобы переопределить полностью построенный объект (поскольку это будет противоречить цели строительства на месте).

Для этой цели система предоставляет два семейства классов, которые в совокупности называются: InPlaceFactories и TypedInPlaceFactories.
По существу, эти классы содержат последовательность фактических параметров и способ построения объекта на месте с использованием этих параметров. Каждый член семейства отличается только количеством (и типом) списка параметров. Первое семейство принимает тип объекта непосредственно в способе, предусмотренном для этой цели, тогда как второе семейство включает этот тип в фабричный класс.

Из контейнера POV использование фреймворка равносильно вызову метода завода для конструирования объекта на месте. От пользователя POV это сводится к созданию правильного заводского объекта для удержания параметров и передачи его в контейнер.
На следующем упрощенном примере показана основная идея. Полный пример следует за формальным описанием структуры:

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") ) ;
}

Specification

Ниже приведен первый член семейства классов «in_place_factory», а также его соответствующая функция шаблона помощника. Остальная часть семейства варьируется только по количеству и типу шаблонных (и конструкторских) параметров.

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);
}

Аналогичным образом, следующее является первым членом семейства классов «typed_in_place_factory», наряду с соответствующей функцией шаблона помощника. Остальная часть семейства варьируется только по количеству и типу шаблонных (и конструкторских) параметров.

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);
}
}

Как вы можете видеть, классы шаблонов «in_place_factory» и «typed_in_place_factory» различаются только тем, как они определяют целевой тип: в первом семействе тип дается в качестве аргумента шаблона для прикладной функции члена, а во втором он дается непосредственно как часть класса завода.
Когда контейнер содержит уникальный неполиморфный тип (например, в случае Boost). Факультативный, он знает точный динамический тип содержащегося объекта и может передать его применяемому() методу (нетипируемого) завода. В этом случае конечные пользователи могут использовать экземпляр «in_place_factory», который может быть построен без типа объекта для строительства.
Однако, если контейнер содержит неоднородные или полиморфные объекты (например, в случае Boost.Variant), динамический тип объекта, который должен быть построен, должен быть известен заводскому ключу. В этом случае конечные пользователи должны использовать «typed_in_place_factory».


Container-side Usage

Как показано во вводном упрощенном примере, класс контейнеров должен содержать методы, которые принимают экземпляр этих заводов и передают хранение объекта применяемому заводом методу.
Однако тип фабрично-заводского класса не может быть полностью указан в классе контейнера, поскольку это повредит всей цели фабрик, которая заключается в том, чтобы позволить контейнеру принять вариадный список аргументов для конструктора его содержащегося объекта.
Перегрузка правильной функции должна основываться на единственной отличительной и общей характеристике всех классов в каждой семье, базовом классе.
В зависимости от класса контейнера вы можете использовать «enable_if» для генерации правильной перегрузки или использовать следующую технику отправки (используется в Boost). Факультативный класс:

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

Конечные пользователи передают контейнеру экземпляр фабричного объекта, содержащего фактические параметры, необходимые для построения содержащегося объекта непосредственно в контейнере. Для этого используется функция шаблона помощника «in_place».
Вызов «in_place (a0,a1,a2,...,an)» конструирует (нетипированный) экземпляр «in_place_factory» с приведенным списком аргументов.
Вызов «in_place(a0,a1,a2,...,an)» конструирует экземпляр «typed_in_place_factory» с приведенным списком аргументов для типа «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
}

Пересмотрено 17 сентября 2004 года

© Copyright Fernando Luis Cacciola Carballal, 2004

Использование, модификация и распространение регулируются Лицензией на программное обеспечение Boost версии 1.0. (См. сопроводительный файлLICENSE_1_0.txtили копию наwww.boost.org/LICENSE_1_0.txt)

РазработанныйФернандо Каччиолой, последняя версия этого файла может быть найдена наwww.boost.org, а также в списках обсуждений

Статья In_place_factory Documentation раздела может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 17:48:09/0.029199838638306/1