Программирование >>  Формирование пользовательского контейнера 

1 ... 13 14 15 [ 16 ] 17 18 19 ... 156


на которую указывает объект-оригинал. Когда копия выходит за пределы области видимости, этот счетчик ссылок уменьшается на единицу.

В действительности дополнительная обработка, выполняемая копирующим конструктором, как правило, не нужна, потому что перефуженные операции присваивания должным образом поддерживают состояние списка сбора мусора в большинстве случаев. Однако существует несколько ситуаций, требующих применения копирующего конструктора, например, при выделении памяти внутри функции и возврате из нее объекта типа GCPtr, указывающего на этот фрагмент памяти.

Операции с указателями и функция преобразования

Поскольку класс ocptr - это тип указателя, он должен перегружать такие операции с указателями, как: *, -> и операцию индексирования []. Это делается с помощью функций, приведенных далее. Предоставляя возможность перефужать указанные операции и создавать, таким образом, новый тип указателя, они еще и приятно радуют своей простотой. Возвращает ссылку на объект, на который указывает этот GCPtr. Т fcoperator*() { return *addr; )

Возвращает адрес, на который указывает. Т *operator->() { return addr;}

Возвращает ссылку на объект с индексом, заданным i. Т &qp€rator[](int i) { return addr[i];

Функция operator* () возвращает ссылку на объект, адрес которого хранится в поле addr активизированного объекта GCPtr, а функция operator-> - адрес, содержащийся в поле addr, функцию operator [] следует использовать только с объектами GCPtr, ссылающимися на массивы. Как уже упоминалось ранее, класс GCPtr не поддерживает арифметические операции с указателями К примеру, ни операция ++, ни операция - не перегружаются в классе GCPtr. Причина в том, что механизм сбора мусора Предполагает, что объект GCPtr указывает на начало вьщеленного фрагмента



памяти Если указатель объекта GCPtr может быть увеличен, то при сборе мусора адрес, используемый операцией delete, может оказаться неправильным.

У вас есть две возможности выполнить действия, включающие арифметическую обработку указателей. Во-первых, если объект ocptr указывает на размещенный массив, вы можете создать объект iter, который позволит перемещаться по массиву. Эта возможность описана далее. Во-вторых, можно преобразовать указатель типа ocptr в обычный указатель с помощью функции т *, описанной в классе ocptr.

Функция преобразования для Т *. operator Т *() { return addr; )

Эта функция возвращает обычный указатель, который ссылается на адрес, хранящийся в поле addr. Ее можно применять следующим образом. GCPtr<double> gcp = new double(99.2); Double *p;

p = gcp; теперь p указывает на ту же память, что и gcp

Р++; поскольку р - обычный указатель, его значение можно увеличивать

В приведенном примере, поскольку р - обычный указатель, его можно обрабатывать, как любой другой указатель. Конечно, принесут ли подобные манипуляции полезный результат, зависит от содержания вашего приложения.

Основная польза от применения функции преобразования заключается в том, что она позволяет использовать объекты ocptr вместо обычных указателей языка С++ при взаимодействии с созданным ранее кодом, который нуждается в них. Рассмотрим следующий пример. GCPtr<char> str = new char(80); strcpy(str, this is a test ); cout str endl;

Переменная str - указатель типа ocptr, указывающий на данные типа char, - применяется как параметр при вызове функции strcpy. Поскольку эта функция ожидает аргументов типа char *, внутри класса ocPtr автоматически инициируется преобразование в т *, причем в этом случае у т - тип char. То же самое преобразование вызывается автоматически, когда переменная str используется в операторе cout. Таким образом, функция преобразования позволяет объектам ocptr без каких-либо шероховатостей взаимодействовать с существующими в языке С++ функциями и классами. Помните, что указатель типа т *, возвращаемый функцией преобразования, не участвует в сборе мусора и никак не влияет на него. Следовательно, можно освободить динамически выделенную память, даже если обычный указатель языка С++ к этому моменту все еще на нее ссылается. Итак, используйте преобразование т * нечасто и с умом.



функции beginO и end()

Функции beginO И end(), показанные далее, подобны их дубликатам из библиотеки STL.

возвращает Iter для начала вьщеленной памяти. Iter<T> beginO { int size;

if(isArray) size = arraySize; else size = 1;

return Iter<T>(addr, addr, addr + size);

Возвращает Iter для элемента, следующего за последним элементом распределенного в памяти массива. Iter<T> end О { int size;

if (isArray) size = arraySize; else size = 1;

return Iter<T>(addr + size, addr, addr + size);

Функция beginO возвращает объект типа iter, указывающий на начало размещенного массива, чей адрес хранится в поле addr. Функция end о возвращает итератор iter, ссылающийся на элемент, следующий за последним элементом распределенного в памяти массива. Хотя ничто не мешает указателю типа GCPtr, ссылающемуся на одиночный объект, вызвать эти функции, их задача - обрабатывать размещенные в динамической памяти массивы (получение итератора iter для одиночного объекта безвредно, только лишено смысла).

Функция shutdownO

Если в программе объектом GCPtr создается циклическая ссылка, то по завершении приложения остаются размещенные в динамической памяти объекты, которые должны быть удалены. Это важно, потому что они могут иметь деструкторы, которые следует вызвать в программе. Функция ShutdownO решает эту задачу. Эта функция регистрируется функцией atexit о, когда создается первый объект класса GCPtr, как описывалось



1 ... 13 14 15 [ 16 ] 17 18 19 ... 156

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