Программирование >>  Оптимизация возвращаемого значения 

1 ... 57 58 59 [ 60 ] 61 62 63 ... 96


if (this == &rhs) return *this; delete [] data;

data = new char [strlen (rhs. data) + 1]; strcpY(data, rhs.data); return *this;

Если задана такая реализация, то можно представить пять объектов и их значения так, как показано на рис. 5.7.

Hollo

НрПо

НрИо

Hollo

Hello

Рис. 5.7

Избыточность такого подхода очевидна. В идеале хотелось бы, чтобы схема программы была аналогична рис. 5.8.


Рис. 5.8

В памяти хранится только одна копия значения Hello , и его представление совместно используется объектами string, имеющим данное значение.

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

Необходимость сохранять информацию о числе совместно используемых объектов приводит к тому, что идеальная схема должна учитывать существование счетчика ссылок (reference count) - см. рис. 5.9.

(Некоторые называют это число счетчиком использования (use count), но я к ним не отношусь. В языке C-i-i- достаточно стилистических особенностей, и меньше всего он нуждается в терминологической путанице.)




Рис. 5.9

Реализация подсчета ссылок

Создать класс String со счетчиком ссылок несложно, но при этом требуется учесть множество деталей, поэтому сейчас будет рассказано о реализации основных функций - членов такого класса. Но сначала важно понять, что необходимо выделить память под каждый счетчик ссылок для всех значений String. Память не должна находиться в объекте String, так как нужен один счетчик для каждого значения строки, а не для каждого объекта. Это подразумевает наличие связи между значениями и счетчиками ссылок, поэтому стоит создать класс для хранения счетчиков ссылок и отслеживаемых ими значений. Назовем его stringValue, и поскольку весь смысл его создания заключается в том, чтобы помочь нам реализовать класс String, то поместим его в закрытую область класса String. Кроме этого, было бы удобно предоставить всем функциям - членам класса string полный доступ к структуре данных класса StringValue, поэтому объявим String-Value как struct. Это полезный прием: помещение структуры в закрытую часть класса является обычным способом обеспечить доступ к структуре членам класса, закрыв его для всех остальных (конечно же, за исключением дружественных классов).

Код мог бы выглядеть примерно так:

class String { public:

private:

struct StringValue {

StringValue *value;

Здесь находятся функции - члены класса String.

Содержит счетчик ссылок

и-значение строки.

Значение класса String.

Вы можете дать этому классу другое имя (например, RCString), чтобы подчеркнуть, что он реализован с применением счетчика ссылок, но реализация класса не должна волновать его пользователей, которых обычно интересует только открытый интерфейс класса. Реализация интерфейса String со счетчиком ссылок поддерживает те же самые операции, что и версия без него, поэтому зачем усложнять программу, включая в имена классов, соответствующих абстрактным понятиям, сведения об их реализации?



Вот код класса StringValue:

class String { private:

struct StringValue { int refCount; char *data;

StringValue(const char *initValue); -StringValue();

String::StringValue::StringValue(const char *initValue)

: refCount(l)

data = new char [strlen (initValue) + 1] ; strcpY(data, initValue);

String::StringValue::-StringValue() {

delete [] data;

Только и всего, но, как вы понимаете, это совсем не полная реализация нужной функциональности. Во-первых, не реализованы ни конструктор копирования, ни оператор присваивания, во-вторых, не обрабатывается поле ref Count. Не беспокойтесь - отсутствующие функции обеспечит класс String. Класс String-Value в основном предназначен для того, чтобы связать определенное значение со счетчиком числа объектов типа string, совместно использующих это значение. Теперь можно перейти к функциям - членам класса String. Начнем с конструкторов:

class String { public:

String(const char *initValue = ) ; String(const Strings rhs);

Первый конструктор реализован настолько просто, насколько возможно. Для создания объекта StringValue используется передаваемая строка char*:

string::string(const char *initValue) : value(new StringValue(initValue)) {}

Для следующего пользовательского кода:

string sCMore Effective С++ );

получится структура данных, которая выглядит примерно так, как показано на рис. 5.10.



1 ... 57 58 59 [ 60 ] 61 62 63 ... 96

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