Возможности по реализации автоматического управления памятью в C++
Несмотря на отсутствие сборки мусора в C++, его, в общем-то, несложно реализовать самому. Предлагаю один из примеров такой реализации.
1. Опишем базовый класс, который будет прародителем всех объектных классов. Назовем его, скажем, CUniObject. Единственным членом класса будет счетчик ссылок (unsigned int count). Счетчик ссылок будет приватным.
2. Описываем класс универсального указателя CUniPointer и вместо указателей на объекты будем создавать экземпляры этого класса. Для поддержки безопасности типов класс CUniPointer следует объявить шаблонным (например, так: template class CUniPointer
3. Чтобы класс указателя мог иметь непосредственный доступ к счетчику ссылок своего типа-параметра, класс CUniPointer следует объявить дружественным в каждом производном классе от CUniObject (friend class CUniPointer<ЭтотКласс>).
4. Объявим два конструктора: первый — конструктор по умолчанию — предназначен для создания неинициализированных объектов-указателей (pointer = NULL), второй — для инициализированных. Последний будет принимать параметром ссылку на другой объект. Другая версия инициализирующего конструктора будет принимать параметр-указатель (для того, чтобы мы могли объявить переменную вот так: CUniPointer
5. В момент присваивания объекту-указателю нового значения счетчики ссылок старого объекта и нового объекта следует также менять. Для этого перегрузим оператор = в классе CUniPointer примерно таким образом:
template
&CUniPointer
{
if (pointer != NULL)
pointer->count—;
pointer = new_ptr;
if (pointer != NULL)
pointer->count++;
return *this;
}
Таким образом, если раньше объект-указатель на что-то указывал, счетчик ссылок этого объекта уменьшим, поскольку теперь объект-указатель на него указывать не будет. Напротив, счетчик ссылок нового объекта увеличим, конечно, в том случае, если новый указатель не пуст.
6. Деструктор объекта-указателя должен также уменьшать счетчик ссылок, если pointer не пуст.
7. Остается добавить в оператор = и в деструктор специальный код, проверяющий счетчик ссылок объекта на равенство нулю, и уничтожающий объект в случае равенства. Таким образом, окончательный вид оператора = будет таков:
template
&CUniPointer
{
if (pointer != NULL)
if (—(pointer->count) == 0)
delete pointer;
pointer = newptr;
if (pointer != NULL)
pointer-count++;
return *this;
}
Дополнительно ко всему этому можно перегрузить оператор = с параметром типа CUniPointer
template
basetype *CUniPointer
{
return pointer;
}
В результате этих действий мы, по сути, получим эмулятор сборщика мусора.
Замечу, что в стандарте C++ предусмотрен специальный класс — автоуказатель — который несколько похож на описанный выше CUniPointer и самостоятельно уничтожает содержащийся внутри него указатель в своём деструкторе. Это класс template
Остается только отметить, что и класс autoptr, и CUniPtr обладают хорошим свойством: прекрасно работают в условиях обработки исключений. Другими словами, объект autoptr или CUniPtr автоматически будет уменьшать счетчик ссылок и уничтожать указатель при условии счетчик = 0 даже тогда, когда произойдет исключение.
В следующей статье я расскажу об управлении памятью «изнутри» — как устроена система управления памятью с точки зрения операционных систем, языков программирования, сред разработки.
Апрель
11,
2008
— Filed under: C++
Метки: C++, управлении памятью
