81
Ведение статистики класса
Также несложно организовать накопление статистики об использовании операторов
Type*
и
->
в
статических переменных параметризованного класса.
template
class SPCS {
private:
Type*
pointer;
static
int
conversions;
static
int
members;
public:
SPCS() : pointer(NULL) {}
SPCS(Type* p) : pointer(p) {}
operator Type*() { conversions++; return pointer; }
Type* operator->() { members++; return pointer; }
int Conversions() { return conversions; }
int Members() { return members; }
};
Глобальные переменные должны быть где-то определены. Обычно это делается в файле Foo.cpp:
// В файле Foo.cpp
int Ptr::conversions = 0;
int Ptr::members = 0;
Разумеется, вы можете воспользоваться директивами
#ifdef
, чтобы это относилось только к
отладочной версии.
Ведение статистики объекта
Мы подошли к более сложной теме. Возможно, ее следует отложить до знакомства с ведущими
указателями (master pointers), однако умные указатели также могут вести статистику по отдельным
объектам, а не по классу в целом. Задача не сводится к тому, чтобы сделать только что показанные
переменные нестатическими (то есть по одному экземпляру переменных на указатель), поскольку мы
(пока) не можем обеспечить однозначное соответствие между указателями и объектами. Вместо этого
статистику придется хранить в самих объектах. Ниже приведен полезный вспомогательный класс,
который можно создать на основе множественного наследования как производный от класса
указываемого объекта и от класса умного указателя, знающего о его свойствах. Объявляя указатель
другом, вы предоставляете ему доступ к защищенным членам классов, производных от
Counter
.
class Counter {
protected:
Counter() : conversions(0), members(0) {}
Counter(const Counter&) : conversions(0), members(0) {}
Counter& operator=(const Counter&) { return *this; }
public:
int
conversions;
int
members;
int Conversions() { return conversions; }
int Members() { return members; }
};
template
class SPOP {
private:
Type*
pointer;
82
public:
SPOS() : pointer(NULL) {}
SPOP(Type* f) : pointer(f) {}
operator Type*() { pointer->conversions++; return pointer; }
Type* operator->() { pointer->members++; return pointer; }
};
На эту тему существует ряд вариаций, с некоторыми из них мы познакомимся при изучении ведущих
указателей.
Кэширование
Иногда нельзя даже настаивать, чтобы объект физически находился в памяти все время, пока к нему
нужен доступ. В следующем примере предполагается, что функция
ReadObject()
умеет использовать
данные о местонахождении объекта на диске, чтобы создать экземпляр и занести его адрес в указатель
pointer
. Если при вызове операторов объект отсутствует в памяти, он автоматически считывается с
диска.
typedef unsigned long DiskAddress; // Заменить нужными данными
template
class CP {
private:
DiskAddress
record_number;
Type*
pointer;
void
ReadObject();
//
Считывает объект с диска
public:
CP(DiskAddress da) : pointer(NULL), record_number(da) {}
CP(Type* f) : pointer(f), record_number(f->RecordNumber()) {}
operator
Type*()
{
if (pointer == NULL) this->ReadObject();
return
pointer;
}
Type*
operator->()
{
if (pointer == NULL) this->ReadObject();
return
pointer;
}
};
Подробно говорить о кэшировании преждевременно, поскольку приходится учитывать множество
проблем, к которым мы еще не готовы. Если вы хотите гарантировать, что читается лишь одна копия
объекта независимо от того, сколько различных объектов на нее ссылается, или чтобы объект
уничтожался сразу после завершения работы операторов, вам придется подождать следующих глав,
посвященных ведущим указателям и управлению памятью. Тем не менее, в простых ситуациях с одним
считыванием, в которых может существовать несколько копий объекта, такая методика достаточно
хорошо работает и с простыми умными указателями.
Кэширующие указатели используют один распространенный прием — они экономят несколько бит за
счет объединения дискового адреса и адреса памяти в одной переменной класса. При этом
используются два упрощающих предположения:
1. Размер адреса памяти не более чем на один бит превышает размер дискового адреса.
2. Средства управления памятью, используемые оператором
new
, никогда не возвращают
нечетный адрес.
Do'stlaringiz bilan baham: |