14.4.1. Инициализация массива, распределенного из хипа A

14.4.1. Инициализация массива, распределенного из хипа A

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

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

#include utility

#include vector

#include new

#include cstddef

#include "Accounts.h"

typedef pairchar*, double

value_pair;

/* init_heap_array()

* объявлена как статическая функция-член

* обеспечивает выделение памяти из хипа и инициализацию

* массива объектов

* init_values: пары начальных значений элементов массива

* elem_count: число элементов в массиве

* если 0, то размером массива считается размер вектора

* init_values

*/

Account*

Account::

init_heap_array(

vectorvalue_pair &init_values,

vectorvalue_pair ::size_type elem_count = 0 )

{

vectorvalue_pair ::size_type

vec_size = init_value.size();

if ( vec_size == 0 && elem_count == 0 )

return 0;

// размер массива равен либо elem_count,

// либо, если elem_count == 0, размеру вектора ...

size_t elems = elem_count

? elem_count : vec_size();

// получить блок памяти для размещения массива

char *p = new char[sizeof(Account)*elems];

// по отдельности инициализировать каждый элемент массива

int offset = sizeof( Account );

for ( int ix = 0; ix elems; ++ix )

{

// смещение ix-ого элемента

// если пара начальных значений задана,

// передать ее конструктору;

// в противном случае вызвать конструктор по умолчанию

if ( ix vec_size )

new( p+offset*ix ) Account( init_values[ix].first,

init_values[ix].second );

else new( p+offset*ix ) Account;

}

// отлично: элементы распределены и инициализированы;

// вернуть указатель на первый элемент

return (Account*)p;

}

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

char *p = new char[sizeof(Account)*elems];

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

for ( int ix = 0; ix

В разделе 14.3 говорилось, что оператор размещения new позволяет применить конструктор класса к уже выделенной области памяти. В данном случае мы используем new для поочередного применения конструктора класса Account к каждому из выделенных элементов массива. Поскольку при создании инициализированного массива мы подменили стандартный механизм выделения памяти, то должны сами позаботиться о ее освобождении. Оператор delete работать не будет:

delete [] ps;

Почему? Потому что ps (мы предполагаем, что эта переменная была инициализирована вызовом init_heap_array()) указывает на блок памяти, полученный не с помощью стандартного оператора new, поэтому число элементов в массиве компилятору неизвестно. Так что всю работу придется сделать самим:

void

Account::

dealloc_heap_array( Account *ps, size_t elems )

{

for ( int ix = 0; ix elems; ++ix )

ps[ix].Account::~Account();

delete [] reinterpret_castchar*(ps);

}

Если в функции инициализации мы пользовались арифметическими операциями над указателями для доступа к элементам:

new( p+offset*ix ) Account;

то здесь мы обращаемся к ним, задавая индекс в массиве ps:

ps[ix].Account::~Account();

Хотя и ps, и p адресуют одну и ту же область памяти, ps объявлен как указатель на объект класса Account, а p - как указатель на char. Индексирование p дало бы ix-й байт, а не ix-й объект класса Account. Поскольку с p ассоциирован не тот тип, что нужно, арифметические операции над указателями приходится программировать самостоятельно.

Мы объявляем обе функции статическими членами класса:

typedef pairchar*, double value_pair;

class Account {

public:

// ...

static Account* init_heap_array(

vector value_pair &init_values,

vector value_pair ::size_type elem_count = 0 );

static void dealloc_heap_array( Account*, size_t );

// ...

};

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Создание распределенного приложения

Из книги Язык программирования С# 2005 и платформа .NET 2.0. [3-е издание] автора Троелсен Эндрю

Создание распределенного приложения Ничто не принесет большей радости, чем создание реального распределенного приложения на новой платформе. Чтобы показать, как быстро можно создать и запустить приложение, использующее слой удаленного взаимодействия .NET, мы построим


Модель распределенного доверия

Из книги Инфраструктуры открытых ключей автора Полянская Ольга Юрьевна

Модель распределенного доверия Модель распределенного доверия разделяет доверие между двумя или несколькими удостоверяющими центрами. Пусть пользователь А владеет копией открытого ключа своего пункта доверия - УЦ1, а пользователь В - копией открытого ключа своего


Облако в погонах: военные системы распределённого моделирования Евгений Лебеденко, Mobi.ru

Из книги Цифровой журнал «Компьютерра» № 97 [28.11.2011 — 04.12.2011] автора Журнал «Компьютерра»

Облако в погонах: военные системы распределённого моделирования Евгений Лебеденко, Mobi.ru Опубликовано 30 ноября 2011 года Современная война — штука высокотехнологичная. Под завязку напичканные электроникой, нынешние средства разрушения всего и вся


8.1.1. Создание и инициализация массива

Из книги Программирование на языке Ruby [Идеология языка, теория и практика применения] автора Фултон Хэл

8.1.1. Создание и инициализация массива Для создания массива применяется специальный метод класса []; перечисленные внутри скобок данные помещаются во вновь созданный массив. Ниже показаны три способа вызвать этот метод. (Массивы а, b и с инициализируются одинаково.)a = Array.[]


8.1.5. Сортировка массива

Из книги Справочник по PHP автора

8.1.5. Сортировка массива Самый простой способ отсортировать массив — воспользоваться встроенным методом sort:words = %w(the quick brown fox)list = words.sort # ["brown", "fox", "quick", "the"]# Или отсортировать на месте:words.sort!       # ["brown", "fox", "quick", "the"]Здесь предполагается, что все элементы массива сравнимы


8.1.10. Рандомизация массива

Из книги Компьютерра PDA N147 (26.11.2011-02.12.2011) автора Журнал «Компьютерра»

8.1.10. Рандомизация массива Иногда нужно переставить элементы массива в случайном порядке. Первое, что приходит на ум, — тасование карточной колоды, но есть и другие применения — например, случайная сортировка списка вопросов.Для решения этой задачи пригодится метод rand из


8.1.18. Обход массива

Из книги VBA для чайников автора Каммингс Стив

8.1.18. Обход массива Как и следовало ожидать, в классе Array есть стандартный итератор each. Но имеются и другие полезные итераторы.Метод reverse_each обходит массив в обратном порядке. Результат такой же, как если бы мы вызвали сначала метод reverse, а потом each, но работает быстрее.words =


8.1.20. Обращение массива

Из книги Язык программирования Си для персонального компьютера автора Бочков C. О.

8.1.20. Обращение массива Чтобы переставить элементы массива в обратном порядке, воспользуйтесь методами reverse или reverse!:inputs = ["red", "green", "blue"]outputs = inputs.reverse # ["green","blue","red"]priorities = %w(eat sleep code)priorities.reverse! #


Создание массива

Из книги Искусство программирования на языке сценариев командной оболочки автора Купер Мендель

Создание массива arrayСоздание и инициализация массива.Синтаксис:array array([mixed ...])Функция возвращает созданный массив. Индексы и значения в массиве разделяются оператором =. Пары index=value разделяются запятыми, они определяют индекс и значение.Индекс может быть как числовым, так


Курсор массива

Из книги Язык Си - руководство для начинающих автора Прата Стивен

Курсор массива resetПроизводит сброс курсора массива.Синтаксис:mixed reset(array arr)Функция reset() устанавливает внутренний курсор массива arr на его начало и возвращает значение начального элемента.Пример использования функции reset():<?php$array = array("step one", "step two", "step three", "step four"); // by default,


Облако в погонах: военные системы распределённого моделирования

Из книги автора

Облако в погонах: военные системы распределённого моделирования Автор: Евгений Лебеденко, Mobi.ruОпубликовано 30 ноября 2011 годаСовременная война - штука высокотехнологичная. Под завязку напичканные электроникой, нынешние средства разрушения всего и вся подчиняются


Данные массива

Из книги автора

Данные массива При работе с массивами нужно помнить следующее.* Можно создавать массивы данных любых типов. VBA с успехом хранит в массивах строки, даты, денежные значения и данные любых числовых типов.* В одном массиве могут храниться данные только одного типа. Нельзя


Объявление массива

Из книги автора

Объявление массива Синтаксис:[<спецификация типа]> <описатель> [<константное выражение>];[<спецификация типа]> <описатель> [];Квадратные скобки, следующие за описателем, являются элементом языка Си, а не признаком необязательности синтаксической


Инициализация двумерного массива

Из книги автора

Инициализация двумерного массива      Для инициализации массива мы взяли пять заключенных в скобки последовательностей чисел, а все эти данные еще раз заключили в скобки. Данные, находящиеся в первых внутренних скобках, присваиваются первой строке массива, данные во


Использование массива

Из книги автора

Использование массива      Предположим, у нас есть массив структур. Имя массива является синонимом его адреса, поэтому его можно передать функции. С другой стороны, функции будет необходим доступ к структурному шаблону. Чтобы показать, как такая программа работает (рис.