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 );
// ...
};
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Создание массива
Создание массива 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,
Данные массива
Данные массива При работе с массивами нужно помнить следующее.* Можно создавать массивы данных любых типов. VBA с успехом хранит в массивах строки, даты, денежные значения и данные любых числовых типов.* В одном массиве могут храниться данные только одного типа. Нельзя
8.1.1. Создание и инициализация массива
8.1.1. Создание и инициализация массива Для создания массива применяется специальный метод класса []; перечисленные внутри скобок данные помещаются во вновь созданный массив. Ниже показаны три способа вызвать этот метод. (Массивы а, b и с инициализируются одинаково.)a = Array.[]
8.1.5. Сортировка массива
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. Рандомизация массива
8.1.10. Рандомизация массива Иногда нужно переставить элементы массива в случайном порядке. Первое, что приходит на ум, — тасование карточной колоды, но есть и другие применения — например, случайная сортировка списка вопросов.Для решения этой задачи пригодится метод rand из
8.1.18. Обход массива
8.1.18. Обход массива Как и следовало ожидать, в классе Array есть стандартный итератор each. Но имеются и другие полезные итераторы.Метод reverse_each обходит массив в обратном порядке. Результат такой же, как если бы мы вызвали сначала метод reverse, а потом each, но работает быстрее.words =
8.1.20. Обращение массива
8.1.20. Обращение массива Чтобы переставить элементы массива в обратном порядке, воспользуйтесь методами reverse или reverse!:inputs = ["red", "green", "blue"]outputs = inputs.reverse # ["green","blue","red"]priorities = %w(eat sleep code)priorities.reverse! #
Создание распределенного приложения
Создание распределенного приложения Ничто не принесет большей радости, чем создание реального распределенного приложения на новой платформе. Чтобы показать, как быстро можно создать и запустить приложение, использующее слой удаленного взаимодействия .NET, мы построим
Инициализация двумерного массива
Инициализация двумерного массива Для инициализации массива мы взяли пять заключенных в скобки последовательностей чисел, а все эти данные еще раз заключили в скобки. Данные, находящиеся в первых внутренних скобках, присваиваются первой строке массива, данные во
Использование массива
Использование массива Предположим, у нас есть массив структур. Имя массива является синонимом его адреса, поэтому его можно передать функции. С другой стороны, функции будет необходим доступ к структурному шаблону. Чтобы показать, как такая программа работает (рис.
Объявление массива
Объявление массива Синтаксис:[<спецификация типа]> <описатель> [<константное выражение>];[<спецификация типа]> <описатель> [];Квадратные скобки, следующие за описателем, являются элементом языка Си, а не признаком необязательности синтаксической
Облако в погонах: военные системы распределённого моделирования Евгений Лебеденко, Mobi.ru
Облако в погонах: военные системы распределённого моделирования Евгений Лебеденко, Mobi.ru Опубликовано 30 ноября 2011 года Современная война — штука высокотехнологичная. Под завязку напичканные электроникой, нынешние средства разрушения всего и вся
Модель распределенного доверия
Модель распределенного доверия Модель распределенного доверия разделяет доверие между двумя или несколькими удостоверяющими центрами. Пусть пользователь А владеет копией открытого ключа своего пункта доверия - УЦ1, а пользователь В - копией открытого ключа своего
Облако в погонах: военные системы распределённого моделирования
Облако в погонах: военные системы распределённого моделирования Автор: Евгений Лебеденко, Mobi.ruОпубликовано 30 ноября 2011 годаСовременная война - штука высокотехнологичная. Под завязку напичканные электроникой, нынешние средства разрушения всего и вся подчиняются