|
Программирование >> Инициализация объектов класса, структура
увы! это не совсем правильно оператор delete. Однако написать delete pact; недостаточно, так как pact при этом не идентифицируется как массив объектов. В результате деструктор класса Account применяется лишь к первому элементу массива. Чтобы применить его к каждому элементу, мы должны включить пустую пару скобок правильно: показает, что pact адресует массив между оператором delete и адресом удаляемого объекта: delete [] pact; Пустая пара скобок говорит о том, что pact адресует именно массив. Компилятор определяет, сколько в нем элементов, и применяет деструктор к каждому из них. 14.4.1. Инициализация массива, распределенного из хипа A По умолчанию инициализация массива объектов, распределенного из хипа, проходит в два этапа: выделение памяти для массива, к каждому элементу которого применяется конструктор по умолчанию, если он определен, и последующее присваивание значения каждому элементу. Чтобы свести инициализацию к одному шагу, программист должен вмешаться и поддержать следующую семантику: задать начальные значения для всех или некоторых элементов массива и гарантировать применение конструктора по умолчанию для тех элементов, начальные значения которых не заданы. Ниже приведено одно из возможных программных решений, где используется оператор размещения new: Не существует способа явно указать начальные значения элементов массива, память для которого выделена из хипа. Если класс поддерживает создание динамических массивов с помощью оператора new, он должен либо иметь конструктор по умолчанию, либо не иметь никаких конструкторов. На практике почти у всех классов есть такой конструктор. Объявление Account *pact = new Account [ 10 ]; создает в памяти, выделенной из хипа, массив из десяти объектов класса Account, причем каждый инициализируется конструктором по умолчанию. Чтобы уничтожить массив, адресованный указателем pact, необходимо применить #include <utility> #include <vector 4таа1т,а таатт-т. #include <new> #include <cstddef> 4таа1т,а Лааапаао #include Accounts.h typedef pair<char*, double> value pair; /* init heap array() объявлена как статическая функция-член обеспечивает в1деление памяти из хипа и инициазацию * массива объектов * init values: пары начальных значений * elem count: число элементов в массиве значений элементов массива если 0, то размером массива считается размер вектора init values Account* Account:: init heap array( vector<value pair> sinit values, vector<value pair>::size type elem count = 0 ) vector<value 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; Необходимо заранее выделить блок памяти, достаточный для хранения запрошенного массива, как массив байт, чтобы избежать применения к каждому элементу конструктора по умолчанию. Это делается в такой инструкции: for ( int ix = 0; ix < elems; ++ix ) { if ( ix < vec size ) new( p+offset*ix ) Account( init values[ix].first, init values[ix].second ); else new( p+offset*ix ) Account; задана пара начальных значений, либо конструктор по умолчанию: В разделе 14.3 говорилось, что оператор размещения new позволяет применить конструктор класса к уже выделенной области памяти. В данном случае м1 используем 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 cast<char*>(ps); неизвестно. Так что всю работу придется сделать самим: Если в функции инициализации мы пользовались арифметическими операциями над указателями для доступа к элементам: new( p+offset*ix ) Account; то здесь мы обращаемся к ним, задавая индекс в массиве ps: ps[ix].Account::~Account(); Хотя и ps, и p адресуют одну и ту же область памяти, ps объявлен как указатель на объект класса Account, а p - как указатель на char. Индексирование p дало бы ix- й байт, а не ix-й объект класса Account. Поскольку с p ассоциирован не тот тин, что нужно, char *p = new char[sizeof(Account)*elems]; Далее программа в цикле обходит этот блок, присваивая на каждой итерации переменной p адрес следующего элемента и вызывая либо конструктор с двумя параметрами, если
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |