Умный (интеллектуальный) указатель — это тот же обычный указатель, обеспечивающий безопасность благодаря автоматическому управлению памятью. Такой указатель помогает избежать множества проблем: «висячие» указатели, «утечки» памяти и отказы в выделении памяти. Интеллектуальный указатель должен подсчитывать количество ссылок на указанный объект.
На первый взгляд эта задача кажется довольно сложной, особенно если вы не эксперт в C++. Один из полезных подходов к решению — разделить задачу на две части: 1) обрисовать общий подход и создать псевдокод, а затем 2) написать подробный код.
Нам нужна переменная — счетчик ссылок, которая будет увеличиваться, как только мы добавляем новую ссылку на объект, и уменьшаться, когда мы ее удаляем. Наш псевдокод может иметь следующий вид:
template
class SmartPointer {
/* Класс интеллектуального указателя нуждается в указателях на собственно
* себя и на счетчик ссылок. Оба они должны быть указателями, а не реальным
* объектом или значением счетчика ссылок, так как цель интеллектуального
* указателя - в подсчете количества ссылок через множество интеллектуальных
* указателей н один объект */
T * obj;
unsigned * ref_count;
}
Для этого класса нам потребуется конструктор и деструктор, поэтому опишем их:
SmartPointer(T * object) {
/* Мы хотим установить значение T * obj и установить счетчик
* ссылок в 1. */
}
SmartPointer(SmartPointer & sptr) {
/* Этот конструктор создает новый интеллектуальный указатель на существующий
* объект. Нам нужно сперва установить obj и ref_count
* такими же, как в sptr. Затем,
* поскольку мы создали новую ссылку на obj, нам нужно
* увеличить ref_count. */
}
~SmartPointer(SmartPointer sptr) {
/* Уничтожаем ссылку на объект. Уменьшаем
* ref_count. Если ref_count = 0, освобождаем память и
* уничтожаем объект. */
}
Существует дополнительный способ создания ссылок — установка одного SmartPointer в другой. Нам понадобится переопределить оператор =
для обработки этого случая, но сначала давайте сделаем набросок кода:
onSetEqals(SmartPointer ptr1, SmartPointer ptr2) {
/* Если ptr1 имеет существующее значение, уменьшить его количество ссылок.
* Затем копируем указатели obj и ref_count. Наконец,
* так как мы создали новую ссылку, нам нужно увеличить
* ref_count. */
}
Осталось только написать код, а это дело техники:
template
class SmartPointer {
public:
SmartPointer(T * ptr) {
ref = ptr;
ref_count = (unsigned*)malloc(sizeof(unsigned));
*ref_count = 1;
}
SmartPointer(SmartPointer & sptr) {
ref = sptr.ref;
ref_count = sptr.ref_count;
++(*ref_count);
}
/* Перезаписываем оператор равенства (eqal), поэтому когда вы установите
* один интеллектуальный указатель в другой, количество ссылок старого указателя
* будет уменьшено, а нового - увеличено.
*/
SmartPointer & operator=(SmartPointer & sptr) {
/* Если уже присвоено объекту, удаляем одну ссылку. */
if (*ref_count > 0) {
remove();
}
if (this != &sptr) {
ref = sptr.ref;
ref_count = sptr.ref_count;
++(*ref_count);
}
return *this;
}
~SmartPointer() {
remove(); // удаляем одну ссылку на объект.
}
T operator*() {
return *ref;
}
protected:
void remove() {
--(*ref_count);
if (ref_count == 0) {
delete ref;
free(ref_count);
ref = NULL;
ref_count = NULL;
}
}
T * ref;
unsigned * ref_count;
}
Разбор задачи по книге «Карьера программиста. Как устроиться на работу в Google, Microsoft или другую ведущую IT-компанию»
Наши тесты для вас:
— Тест на знание сленга веб-разработчиков.
— Что вы знаете о работе мозга?
— А вы точно программист?