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

1 ... 64 65 66 [ 67 ] 68 69 70 ... 96


if {value->isShared{)) {

value = new StringValue{value->data);

value->markUnshareable(); return value->data[index];

Если вы сравните этот код класса string с кодом, который был разработан при помощи обычных указателей, то будете поражены двумя вещами. Во-первых, класс стал намного меньше, поскольку класс RCPtr принимает на себя основные функции, которые выполнял класс String. Во-вторых, код, оставшийся в классе String, практически не изменился: интеллектуальный указатель почти незаметно заменил обычный. Единственное новшество коснулось функции operator [ ], где вызывается функция is shared вместо прямой проверки значения refCount, а применение объекта интеллектуального указателя RCPtr устраняет необходимость врзную изменять счетчик ссылок во время копирования при записи.

Все это замечательно. Кто возражает против уменьшения кода? Кто против успешного применения инкапсуляции? Но итог скорее определяется не деталями реализации, а тем, как новоиспеченный класс string воспринимается пользователями, и именно здесь его преимущество наиболее очевидно. Если отсутствие новостей - хорошие новости, тогда то, что интерфейс класса String не изменился -действительно хорошо. Вы добавили к нему подсчет ссылок и возможность помечать отдельные значения строк как недоступные для совместного использования, затем переместили подсчет ссылок в новый базовый класс, включили в код интеллектуальные указатели для автоматизации обработки подсчета ссылок, и при этом ни одна строка пользовательского кода не изменилась. Конечно, было изменено определение класса, поэтому для того, чтобы использовать строки со счетчиком ссылок, пользователям придется снова выполнить компиляцию и компоновку, но их капиталовложения в разработанный код остаются в целости и сохранности. Видите? Инкапсуляция - это действительно замечательная вещь.

Добавление подсчета ссылок к существующим классам

До сих пор предполагалось, что вам доступен исходный код интересующих вас классов. Но как быть, если нужно использовать подсчет ссылок в каком-то классе Widget, находящемся в библиотеке, которую вы не можете изменять? Нельзя сделать Widget наследником класса RCObject, поэтому недопустимо использовать в нем интеллектуальные указатели RCPtr. Однако, слегка изменив схему, вы можете добавить подсчет ссылок к любому типу.

Во-первых, рассмотрим, как бы выглядела схема, если бы была возможность сделать класс Widget наследником класса RCObj ect. В этом случае пришлось бы добавить класс RCWidget, с которым работали бы пользователи, и классы RCWidget и Widget были бы аналогичны соответственно классам String и StringValue в рассмотренном примере. Схема такой программы приведена на рис. 5.16.



объект f

класс

RCObject

Открытое

наследование

Указатель


Рис. 5.16

Теперь стоит вспомнить принцип, который гласит, что большинство проблем теории программирования можно решить, добавив еще один уровень косвенной адресации. Добавим для счетчика ссылок еще один класс CountHolder и сделаем класс CountHolder наследником класса RCObject. Также включим в класс CountHolder указатель на Widget. Затем заменим шаблон RCPtr таким же интеллектуальным шаблоном RCIPtr, который знает о существовании класса CountHolder. (Буква I в названии класса RCIPtr означает indirect, то есть косвенный.) Измененная схема представлена на рис. 5.17.

объекг


Открытое наследование

и объект

Указатель V

Рис. 5.17



Ниже объясняется, почему эти функции объявлены таким образом.

Так же как детали реализации класса StringValue скрыты от пользователей класса String, класс CountHolder является одной из деталей реализации, скрытой от пользователей класса RCWidget. Фактически, это одна из деталей реализации класса RCIPtr, поэтому данный класс вложен в класс RCIPtr, реализованный следующим образом:

template<class Т> class RCIPtr { public:

RCIPtr(Т* realPtr = 0) ;

RCIPtr(const RCIPtrb rhs);

-RCIPtr0;

RCIPtrSc operator= (const RCIPtrb rhs) ; const T* operator->() const; T* operator->(); const TSc operator* 0 const; TSc operator* () ; private:

struct CountHolder: public RCObject { -CountHolder() { delete pointee; } T *pointee;

CountHolder *counter; void init () ; void makeCopy () ;

template<class T> void RCIPtr<T>::init () {

if (counter->isShareable() == false) { T *oldValue = counter->pointee; counter = new CountHolder; counter->pointee = new T(*oldValue);

counter->addReference();

template<class T> RCIPtr<T>::RCIPtr(T* realPtr) : counter(new CountHolder) {

counter->pointee = realPtr; initO ;

template<class T>

RCIPtr<T>: :RCIPtr (const RCIPtrSc rhs) : counter(rhs.counter) { initO ; } template<class T> RCIPtr<T>::-RCIPtr0

Cm. ниже.



1 ... 64 65 66 [ 67 ] 68 69 70 ... 96

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