Контейнер, предназначенный для поддержки пустого состояния, обычно не требует, чтобы содержащийся тип был конструктивным по умолчанию, но обычно требует, чтобы он был совместимым с копией в качестве механизма инициализации объекта для хранения:
struct C
{
C() : contained_(0) {}
C ( X const& v ) : contained_ ( new X(v) ) {}
~C() { delete contained_ ; }
X* contained_ ;
} ;
Существует тонкая проблема с этим: поскольку механизм, используемый для инициализации хранимого объекта, представляет собой конструкцию копии, должен существовать ранее построенный объект-источник для копирования. Этот объект, вероятно, будет временным и не будет служить никакой цели, кроме как быть источником.
Решение этой проблемы заключается в поддержке непосредственного строительства содержащегося объекта прямо в контейнере. В этой схеме пользователь поставляет аргументы для конструктора 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 это сводится к созданию правильного заводского объекта для удержания параметров и передачи его в контейнер. На следующем упрощенном примере показана основная идея. Полный пример следует за формальным описанием структуры:
Ниже приведен первый член семейства классов «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:
Аналогичным образом, следующее является первым членом семейства классов «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:
Как вы можете видеть, классы шаблонов «in_place_factory» и «typed_in_place_factory» различаются только тем, как они определяют целевой тип: в первом семействе тип дается в качестве аргумента шаблона для прикладной функции члена, а во втором он дается непосредственно как часть класса завода. Когда контейнер содержит уникальный неполиморфный тип (например, в случае Boost). Факультативный, он знает точный динамический тип содержащегося объекта и может передать его применяемому() методу (нетипируемого) завода. В этом случае конечные пользователи могут использовать экземпляр «in_place_factory», который может быть построен без типа объекта для строительства. Однако, если контейнер содержит неоднородные или полиморфные объекты (например, в случае Boost.Variant), динамический тип объекта, который должен быть построен, должен быть известен заводскому ключу. В этом случае конечные пользователи должны использовать «typed_in_place_factory».
Как показано во вводном упрощенном примере, класс контейнеров должен содержать методы, которые принимают экземпляр этих заводов и передают хранение объекта применяемому заводом методу. Однако тип фабрично-заводского класса не может быть полностью указан в классе контейнера, поскольку это повредит всей цели фабрик, которая заключается в том, чтобы позволить контейнеру принять вариадный список аргументов для конструктора его содержащегося объекта. Перегрузка правильной функции должна основываться на единственной отличительной и общей характеристике всех классов в каждой семье, базовом классе. В зависимости от класса контейнера вы можете использовать «enable_if» для генерации правильной перегрузки или использовать следующую технику отправки (используется в Boost). Факультативный класс:
Конечные пользователи передают контейнеру экземпляр фабричного объекта, содержащего фактические параметры, необходимые для построения содержащегося объекта непосредственно в контейнере. Для этого используется функция шаблона помощника «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
}
Использование, модификация и распространение регулируются Лицензией на программное обеспечение Boost версии 1.0. (См. сопроводительный файлLICENSE_1_0.txtили копию наwww.boost.org/LICENSE_1_0.txt)
РазработанныйФернандо Каччиолой, последняя версия этого файла может быть найдена наwww.boost.org, а также в списках обсуждений
Статья In_place_factory Documentation раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.