|
Программирование >> Оптимизация возвращаемого значения
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.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |