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

1 ... 60 61 62 [ 63 ] 64 65 66 ... 96


value = rhs.value, ++value->refCount;

else {

value = new StringValue(rhs.value->data);

Bee остальные функции - члены класса String должны проверять поле shareable аналогичным образом. Единственная функция, которая будет присваивать флагу shareable значение false, - это не-const версия operator[].

charSc String: : operator [ ] (int index) {

if {value->refCount > 1) { --value->refCount;

value = new StringValue{value->data);

value->shareable = false; Добавить эту строку,

return value->data[index];

Если чтобы различать чтение и запись в operator [ ], вы используете метод proxy-класса из правила 30, скорее всего это приводит к уменьшению числа объектов StringValue, которые должны быть помечены как недоступные для совместного использования.

Базовый класс для подсчета ссылок

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

Первый шаг состоит в создании базового класса RCOb j ect для объектов с подсчетом ссылок, от которого должны наследовать все классы, собираюшиеся использовать автоматический подсчет ссылок. Класс RCOb j ect инкапсулирует счетчик ссылок, а также функции для уменьшения и увеличения этого счетчика. Он также содержит код для уничтожения значения после того, как оно перестает быть нужным, то есть когда счетчик ссылок на него становится равным 0. И наконец, он имеет поле, определяющее, может ли это значение использоваться совместно, и функции для проверки и установки данного значения равным false. Нет необходимости придавать этому полю значение true, так как по умолчанию все значения могут использоваться совместно. Как указано выше, если объект был помечен как недоступный для совместного использования, он остается таким навсегда.



Определение класса RCObject выглядит следующим образом:

class RCObject { public:

RCObjectO ;

RCObject (const RCObjectSc rhs) ; RCObject& operator=(const RCObjectb rhs) ; virtual -RCObjectO = 0; void addReference(); void removeReference0; void markUnshareable(); bool isShareable() const; bool isSharedO const; private:

int refCount; bool shareable;

Объекты RCObject могут создаваться и уничтожаться (как части базового класса в производных классах); к ним могут добавляться новые ссылки и удаляться существующие; разрешается запрашивать и устанавливать значение флага, определяющего возможность их совместного использования; они также могут сообщать, используются ли они уже совместно. Это все, что они способны предложить. Но большего от них как от класса, инкапсулирующего понятие подсчета ссылок, и не ожидалось. Обратите внимание на виртуальный деструктор - верный знак, что класс разработан для использования в качестве базового. Кроме того, деструктор является абстрактной функцией, а это свидетельствует, что класс будет применяться только в качестве базового.

Код класса RCObject достаточно краток:

RCObj ect::RCObj ect() : refCount(0), shareable(true) {} RCObject::RCObject(const RCObject&) : refCount(O), shareable(true) {} RCObject& RCObject::operator=(const RCObjectSc) { return *this; }

RCObject::-RCObject () {} Виртуальные деструкторы должны

быть всегда реализованы, даже если они являются полностью виртуальными и ничего не делают (см. также правило 33) .

void RCObject::addReferenceО { ++refCount; }

void RCObject::removeReference()

{ if (--refCount == 0) delete this; }

void RCObject::markUnshareable()

{ shareable = false; }

bool RCObject::isShareable0 const

{ return shareable; }

bool RCObject::isShared() const

{ return refCount > 1; }



Странно, что в обоих конструкторах счетчику re f Count в конструкторе присваивается значение 0. Интуиция подсказывает обратное. По крайней мере, создатель нового объекта RCObject должен ссылаться на него! Оказывается, проще сделать так, чтобы создатели объектов RCObj ect сами присваивали счетчику ref Count значение 1, поэтому предусмотрено такое поведение конструктора в классе ref Count, которое обязывает их сделать это. Как вы вскоре увидите, в результате код значительно упростится.

Другая странность состоит в том, что конструктор копирования всегда присваивает счетчику ref Count значение О, независимо от значения ref Count в копируемом объекте RCObject. Это объясняется следующим образом: вы создаете новый объект, представляющий значение, а на новые значения всегда ссылается только их создатель, и они не используются совместно. И в этом случае автор объекта отвечает за установку правильного значения счетчика ref Count.

Оператор присваивания класса RCObj ect ведет себя совершенно необычно: он не делает ничего. К счастью, маловероятно, что он будет вызываться вообще. Базовый класс RCObj ect предназначен для объекта совместно используемого значения, и в системе, основанной на подсчете ссылок, такие объекты не присваиваются друг другу, а вместо этого выполняется присваивание для объектов, указывающих на них. В рассматриваемом случае мы не ожидаем, что объекты StringValue будут присваиваться друг другу, предполагается, что присваивание будет выполняться для объектов String. При этом значение StringValue останется неизменным -будет меняться только значение счетчика ссылок.

Тем не менее, существует вероятность, что в каком-то классе, который когда-либо будет наследовать от класса RCObj ect, потребуется разрешить присваивание значений, предусматривающих подсчет ссылок (см. правило 32). И в этом случае оператор присваивания класса RCObject должен сделать то, что нужно, то есть ничего. Чтобы понять, почему это так, представьте, будто вы хотели разрешить присвоение между объектами StringValue. Если имеются объекты svl и sv2 типа StringValue, что произойдет со счетчиками ссылок объектов svl и sv2?

svl = sv2; Что произойдет со счетчиками ссылок

объектов svl и sv2?

До присваивания несколько объектов string указывает на svl. Их число не изменяется в результате присваивания, так как меняется только значение svl. Аналогично, до присваивания какое-то число объектов String указывает на sv2, и после присваивания те же самые объекты String указывают на sv2. Счетчик ссылок на объект sv2 также остается неизменным. Таким образом, при присваивании объектов RCObject число ссылок на эти объекты остается прежним, следовательно, функция RCObj ect: : operator= не должна изменять счетчики ссылок. Это как раз то, что и делает приведенная выше реализация. Интуиция подсказывает обратное? Возможно, но предложенный код все же является корректным.

Код функции RCObject: :removeReference отвечает не только за уменьшение счетчика ссылок ref Count, но и за уничтожение объекта, если новое значение счетчика ref Count равно 0. Функция выполняет последнюю задачу, вызывая delete this, а это безопасно, только если объект *this находится в куче



1 ... 60 61 62 [ 63 ] 64 65 66 ... 96

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