Программирование >>  Составные структуры данных 

1 ... 53 54 55 [ 56 ] 57 58 59 ... 225


функциям. Они работают так, как это описано для класса Complex, однако ведут к неверной семантике копирования и утечке памяти, если какие-нибудь данные-члены являются указателями. Программа 4.21 - суть интерфейс очереди FIFO, в который включены три перечисленных функции. Подобно конструкторам, они имеют отличительные сигнатуры, в которые входит имя класса.

Программа 4.21 Интерфейс АТД первого класса Очередь

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

template <clas$ Item> class QUEUE {

private:

Inplementation-dependent code piiblic:

QUEUE(int);

QUEUE(const QUEUE&);

QUEUES operator=(const QUEUES);

~QUEOE();

int empty0 const; void put(Itern); Item getO ;

Когда при создании объекту присваивается начальное значение либо объект передается как параметр или возвращается из функции, система автоматически вызывает конструктор копирования QUEUE(const QUEUE&). Операция присваивания QUEUE& operator=(const QUEUE&) вызывается в случае применения операции =, дабы присвоить значение одной очереди другой. Деструктор QUEUEO вызывается в том случае, если необходимо освободить память, связанную с какой-либо очередью. Если в программе присутствует объявление без установки начального значения, наподобие QUEUE<int> q;, то для создания объекта q система использует конструктор QUEUE(). Если объект инициализируется с помощью такого объявления, как QUEUE<int> q = р (или эквивалентной формы QUEUE<mt> q(p)), система использует конструктор копирования QUEUE(const QUEUE&). Эта функция должна создавать новую копию объекта р, а не просто еще один указатель на него. Как обычно для ссылочных параметров, ключевое слово const выражает намерение не изменять объект р, но использовать его только для доступа к хранящейся в нем информации.

Программа 4.22 представляет собой реализацию конструктора копирования, пере-фуженной операции присваивания и деструктора для реализации очереди на базе связного списка из программы 4.14. Десфуктор проходит по всей очереди и с помощью delete освобождает память, распределенную под каждый узел. Если клиентская программа присваивает значения некоторого объекта самому себе, то в операции присваивания не предпринимаются каких-либо действий; в противном случае вызывается деструктор, а затем с помощью put копируется каждый элемент очереди, сто-



ящей справа от знака операции. Конструктор копирования обнуляет очередь (т.е. делает ее пустой) и затем с помощью операции присваивания выполняет копирование.

За счет помещения в класс конструктора копирования, перегруженной операции присваивания и деструктора (аналогично тому, как это делается в программе 4.22), можно превратить любой класс языка С++ в АТД первого класса. Эти функции обычно действуют по принципу простого обхода структур данных. Однако эти дополнительные щаги предпринимаются не всегда, поскольку

часто используется только один экземпляр объекта определенного класса;

даже при условии присутствия нескольких экземпляров может оказаться необходимым предотвращение непреднамеренного копирования огромных структур данных.

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

Программа 4.22 Реализация очереди первого класса на базе связного списка

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

Деструктор -QUEUEO вызывает приватную функцию-член deletelist, которая проходит по всему связному списку, вызывая для каждого узла функцию delete. Таким образом, когда освобождается память, связанная с указателями, освобождается также вся память, занимаемая объектом.

Если перегруженная операция присваивания вызывается для случая, когда объект присваивается самому себе (например, q = q), никакие действия не выполняются, В противном случае вызывается функция deletelist, чтобы очистить память, связанную со старой копией объекта (в результате получается пустой список). Затем для каждого элемента списка, который соответствует объекту, находящемуся справа от знака операции присваивания, вызывается put и таким образом создается копия этого списка. В обоих случаях возвращаемое значение представляет собой ссылку на целевой объект (объект, которому присваиваются значения другого объекта).

Конструктор копирования QUEUE(const QUEUE&) обнуляет список и затем с помощью перегруженной операции присваивания создает копию своего аргумента.

private: void deletelistО

for (link t = head; t != 0; head = t) { t = head->next; delete head; }

public: QUEUE(const QUEUE& rhs)

{ head = 0; *this = rhs; } QUEUES operators(const QUEUE& rhs)



if (this == &rhs) return *this;

deletelistO ;

link t = rhs.head;

while (t != 0)

{ put(t->item); t = t->next; } return *this;

-QUEUE 0

{ deletelistO; }

Приведенные рассуждения также объясняют, почему библиотека языка С++ включает класс string, несмотря на привлекательность низкоуровневой структуры данных типа строки в стиле языка С. С-строки не принадлежат к типам данных первого класса, поскольку они не особенно лучше указателей. В самом деле, многие профаммисты впервые сталкиваются с некорректной семантикой копирования тогда, когда копируют указатель на С-строку, ожидая, что будет копироваться сама строка. В противоположность этому, класс string языка С++ является типом данных первого класса, поэтому при работе с большими сфоками следует соблюдать особую осторожность.

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

Утечка памяти - это трудно выявляемый дефект, который словно чума поражает многие большие системы. Хотя освобождение памяти, занятой некоторым объектом, обычно является делом, в принципе, простым, на практике очень тяжело быть уверенным в том, что удалось отыскать все вплоть до последней распределенной области памяти. Механизм десфукторов в языке С++ полезен, однако система не может гарантировать, что обход сфуктур данных совершен так, как задумывалось. Когда объект прекращает свое существование, его указатели теряются безвозвратно, и любой указатель, оставленный без внимания деструктором, потенциально ведет к утечке памяти. Один из типовых источников утечки памяти возникает тогда, когда в



1 ... 53 54 55 [ 56 ] 57 58 59 ... 225

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