Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Назначение механизма подсчета ссылокСодержание книги
Поиск на нашем сайте Сущность метода подсчета ссылок заключается в отделении объекта от соответствующего ему значения. Объект содержит лишь ссылку (указатель) на свое значение, причем на это же значение могут ссылаться и другие объекты. Для учета числа объектов, имеющих некоторое значение V, с этим значением ассоциируется счетчик ссылок (reference count). Этот счетчик изменяется при каждом увеличении или уменьшении числа объектов со значением V; при добавлении объекта он увеличивается на единицу, а при удалении объекта – уменьшается на единицу. Когда значение V становится не нужным ни одному из объектов, его счетчик ссылок оказывается нулевым и оно безопасно удаляется из памяти. Объекты разделяют значение V до тех пор, пока один из них не «захочет» его изменить. В этом случае для такого объекта создается отдельная копия значения V, которая может быть модифицирована без влияния на значение других объектов, а счетчик ссылок значения V получает отрицательное единичное приращение. Такое копирование значения при попытке его изменения принято называть копированием при записи (copy on write). Контекстно-независимая модель счетчика ссылок Подсчет ссылок является контекстно-независимым методом, что позволяет инкапсулировать его в отдельном базовом классе (хотя применение отдельного класса вовсе не обязательно, оно способствует улучшению качества проекта, создавая благоприятные условия к повторному использованию кода и увеличивая уровень инкапсуляции). Подключая этот класс к любому пользовательскому классу, например, путем вложения или наследования, можно обеспечить поддержку подсчета ссылок для пользовательского класса. Класс подсчета ссылок можно применять и для модификации стандартных классов, если необходимо придать им функциональность подсчета ссылок. Класс для подсчета ссылок (назовем его RefCounter) должен инкапсулировать следующие возможности: а) хранение значения счетчика ссылок; б) увеличение и уменьшение счетчика ссылок; в) удаление значения объекта при нулевом счетчике ссылок; г) управление разрешением на совместное использование значения объекта. Вариант определения класса RefCounter имеет вид: class RefCounter { public: RefCounter(); RefCounter(const RefCounter &); RefCounter & operator = (const RefCounter &); virtual ~RefCounter() = 0; Void AddRef(); // добавить ссылку Void RemoveRef(); // убрать ссылку Bool isShareable() const; // проверка возможности совместного доступа Bool isShared() const; // проверка совместного доступа Void MakeUnshareable(); // запретить совместный доступ private: size_t _refcount; // счетчик ссылок bool _shareable; // признак разрешения совместного доступа }; Реализация этого класса будет следующей: RefCounter::RefCounter(): _refcount(0), _shareable(true) {} RefCounter::RefCounter(const RefCounter &): _refcount(0), _shareable(true) {} RefCounter & RefCounter::operator = (const RefCounter &) { return *this; } RefCounter::~RefCounter() {} void RefCounter::AddRef() { _refcount++; } void RefCounter::RemoveRef() { if(--_refcount == 0) delete this; } bool RefCounter::isShareable() const { return _shareable; } bool RefCounter::isShared() const { return _refcount > 1; } void RefCounter::MakeUnshareable() { _shareable = false; } Функции класса RefCounter выглядят обычно, за исключением, пожалуй, конструкторов и операции присваивания. В обоих конструкторах начальное значение счетчика ссылок равно нулю. Создатели объектов класса RefCounter должны самостоятельно устанавливать его в единицу (в конечном счете это ведет к упрощению кода). Операция присваивания вполне законно не делает никакой работы, поскольку объекты – счетчики ссылок не копируются; вместо них копируется значение, с которым они ассоциированы. Класс RefCounter абстрактный за счет чисто виртуального деструктора, поэтому объект – счетчик ссылок можно создать только как часть объекта производного класса, который использует возможности подсчета ссылок. Внедрение подсчета ссылок в новый класс Теперь воспользуемся введенным классом. Для этого определим какой-нибудь пользовательский класс и реализуем в нем подсчет ссылок из класса RefCounter. Пусть таким классом будет класс поименованных одномерных массивов с произвольным диапазоном индексов. Определение класса имеет вид: class NamedArray { public: NamedArray(double * items, int lbound, int hbound, const string & name); NamedArray(const NamedArray & sample); const double & operator [] (int i) const; double & operator [] (int i); friend ostream & operator << (ostream & os, const NamedArray & array); ~NamedArray(); private: // вложенный класс – значение массива со счетчиком ссылок struct ArrayValue: public RefCounter { ArrayValue(double * items, int lbound, int hbound, const string & name); ArrayValue(const ArrayValue & value); ~ArrayValue() { delete[] _items; } double * _items; // элементы массива int _lbound; // нижний индекс int _hbound; // верхний индекс string _name; // имя массива }; // указатель, связывающий объект со значением и счетчиком ссылок ArrayValue * _pValue; NamedArray(); // конструктор по умолчанию делаем недоступным }; Реализация функций класса NamedArray следующая: // конструктор значения массива NamedArray::ArrayValue::ArrayValue(double * items, int lbound, int hbound, const string & name) { size_t size = hbound - lbound + 1; _items = new double [size]; for(size_t i=0; i<size; ++i) _items[i] = items[i]; _lbound = lbound; _hbound = hbound; _name = name; } // конструктор копирования значения NamedArray::ArrayValue::ArrayValue(const ArrayValue & value) { size_t size = value._hbound - value._lbound + 1; _items = new double [size]; for(size_t i=0; i<size; ++i) _items[i] = value._items[i]; _lbound = value._lbound; _hbound = value._hbound; _name = value._name; } // конструктор массива NamedArray::NamedArray(double * items, int lbound, int hbound, const string & name): _pValue(new ArrayValue(items,lbound,hbound,name)) { } // конструктор копирования массива NamedArray::NamedArray(const NamedArray & sample) { if(sample._pValue->isShareable()) { this->_pValue = sample._pValue; _pValue->AddRef(); } else _pValue = new ArrayValue(*sample._pValue); } // деструктор массива NamedArray::~NamedArray() { delete _pValue; } // индексация const double & NamedArray::operator [] (int i) const { return _pValue->_items[i - _pValue->_lbound]; } double & NamedArray::operator [] (int i) { if(_pValue->isShared()) { _pValue->RemoveRef(); _pValue = new ArrayValue(_pValue->_items, _pValue->_lbound, _pValue->_hbound, _pValue->_name); } _pValue->MakeUnshareable(); return _pValue->_items[i - _pValue->_lbound]; } // вывод ostream & operator << (ostream & os, const NamedArray & array) { for(int i=0; i<array._pValue->_hbound-array._pValue->_lbound+1; ++i) os << array._pValue->_items[i] << " "; return os; } Ниже приведен пример использования класса NamedArray в программе. Пример double items[] = { 0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0 }; // создание исходного массива NamedArray a1(items, 1, 10, "array"); // создание копии массива // здесь значение не копируется, а увеличивается счетчик ссылок NamedArray a2(a1); // здесь тоже значение не копируется, увеличивается счетчик ссылок NamedArray a3 = a2; cout << endl << "Array1 = " << a1; // 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 cout << endl << "Array2 = " << a2; // 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 cout << endl << "Array3 = " << a3; // 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 // здесь необходимо скопировать значение, так как оно меняется a3[1] = 9.99; // здесь создается копия объекта и копия значения, так как // значение a3 больше нельзя использовать совместно NamedArray a4(a3); cout << endl << "Array1 = " << a1; // 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 cout << endl << "Array2 = " << a2; // 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 cout << endl << "Array3 = " << a3; // 9.99 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 cout << endl << "Array4 = " << a4; // 9.99 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 Реализацию подсчета ссылок и копирование при записи аналогично можно обеспечить в любом другом пользовательском классе, где объекты могут иметь совпадающие значения. Эти механизмы поддерживаются также во многих стандартных классах, например, в шаблонном классе basic_string, представляющем строки символов. В принципе, подсчет ссылок разумно использовать тогда, когда есть вероятность, что много объектов класса будут иметь одинаковые значения, причем эти значения будут редко изменяться.
|
||
|
Последнее изменение этой страницы: 2016-08-14; просмотров: 300; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.216.196 (0.007 с.) |