Программирование >>  Перегруженные имена функций и идентификаторы 

1 ... 129 130 131 [ 132 ] 133 134 135 ... 210


if( CRC OK( dataStream ) ) {

определяем тип конкретного результата

и строим соответствующий объект прямо на месте

себя

switch( AnalysisOf( dataStream ) ) { case PHLEGM:

::new( this ) Phlegm( dataStream );

break; case BLOOD:

::new( this ) Blood( dataStream );

break;

case

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

Менеджер памяти создан, инициализирован. Пул памяти существует (хотя бы от обычного malloc, а хоть и с потолка - ваше дело). Есть некоторый поток байт (пусть он зовётся stream), в котором то, с чем мы и боремся. Объект создаётся следующим образом:

BCAR *analysis = new BCAR( stream );

Обратите внимание - мы создаём объект класса BCAR. В первую очередь вызывается BCAR::new, который в действительности завуалированный MemoryManager.largest(). Мы имеем адрес в свободной памяти, где и создаётся объект BCAR и запускается его конструктор BCAR::BCAR( const unsigned char * ). В конструкторе по информации из заголовка (полученного из потока stream) выясняется точный тип анализа и через глобальный new (который не делает ничего) создаётся на месте объекта BCAR объект уточнённого типа. Начинает исполняться его конструктор, который в свою очередь вызывает конструктор BCAR::BCAR(). Надеемся, стало понятно почему BCAR::BCAR() определяется с пустым телом. Потом в конструкторе конкретного объекта вызывается MemoryManager.alloc( int ), благодаря чему менеджер памяти получает информацию о точном размере объекта и соответствующим образом правит свои структуры.



Уничтожение объектов примитивно, ибо всей необходимой информацией MemoryManager располагает:

void BCAR::operator delete( void *p ) {

MemoryManager.free( (BCAR *)p, ((BCAR *)p)->size() );

Переносимость этой конструкции очень высока, хотя может понадобиться некоторая правка для весьма экзотических машин. Факты же таковы, что она используется в трёх очень крупных мировых центрах на четырёх аппаратных платформах и пяти операционках.

Ho это ещё не всё. Как особо дотошные могли заметить - здесь присутствует виртуальность конструктора, но в любом случае объект конкретного класса всё равно имеет фиксированный размер. А вот объектов одного класса, но разного размера нет. До относительно недавнего времени нас это вполне устраивало, пока не появились некоторые требования, в результате которых нам пришлось сделать и это. Для этого у нас есть два (по меньшей мере) способа. Один - переносимый, но неэстетичный, а второй - непереносимый, но из common practice. Эта самая common practice состоит в помещении последним членом класса конструкции вида unsigned char storage[ 1 ] в расчёте на то, что это будет действительно последним байтом во внутреннем представлении объекта и туда можно записать не байт, а сколько надо. Стандарт этого вовсе не гарантирует, но практика распространения нашего детища показала, что для применяемых нами компиляторов оно именно так и есть. И оно работает. Чуть-чуть поправим наши объекты:

class Blood: public BCAR {

friend BCAR;

private:

int bodySize;

int size() { return sizeof( Blood ) + bodySize; } int getSize( const char * ); sturct BloodAnalysisBody {

тут его поля } *body;

Blood( const unsigned char *data ): BCAR() { body = (BloodAnalysisBody *) bodyStorage;



bodySize = getSize( data ); ::memcpy( bodyStorage, data + sizeof( header ), bodySize );

MemoryManager.alloc( size() );

unsigned char bodyStorage[ 1 ];

Бороться с данными далее придётся через body->, но сейчас мы не об этом

Однако вспомним, что менеджер памяти у нас свой в доску , и мы можем обойтись действительно переносимой конструкцией. Тело анализа достаточно разместить сразу за самим объектом, статический размер которого нам всегда известен. Ещё чуть-чуть правим:

class Blood: public BCAR {

friend BCAR;

private:

int bodySize;

int size() { return sizeof( Blood ) + bodySize; } int getSize( const unsigned char * ); struct BloodAnalysisBody {

тут его поля } *body;

Blood( const unsigned char *data ): BCAR() {

body = (BloodAnalysisBody *) ((unsigned char *)this + sizeof( Blood ));

bodySize = getSize( data );

::memcpy( body, data + sizeof( header ), bodySize ); MemoryManager.alloc( size() );

Данные гарантированно ложатся сразу за объектом в памяти, которую нам дал MemoryManager (а он, напомним, даёт нам всегда максимум из того, что имеет), а затем alloc соответствующим образом всё подправит.



1 ... 129 130 131 [ 132 ] 133 134 135 ... 210

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика