Идиомы и стили С++ (Махмутов) - страница 4

> ~SmartPointer(){ if (tObj) delete tObj; }

> operator T*(){ return tObj; }

> T* operator-›(){ return tObj; }

>};

Для интереса посмотрите, как сделан auto_ptr в STL.

Передохнем. Кофе. Джоггинг. Пиво. Сигарета. Нужное подчеркнуть, выпить, покурить.

Шаг 3 - Как это применять.

Берем код параметризированного класса.

>template ‹class T›

>class SmartPointer {

>private:

> T* tObj;

>public:

> SmartPointer(T* _t=NULL): tObj(_t);

> ~SmartPointer() {if (tObj) delete tObj;}

> operator T*(){return tObj;}

> T* operator-›(){return tObj;}

>};

1. Обработка обращения к NULL.

Заменяем реализацию оператора -› на:

>T* operator-›() {

> if (!tObj) {

>  cerr ‹‹ "NULL";

>  tObj = new T;

> }

> return tObj;

>}

или

>T* operator-›() {

> if (!tObj) throw CError;

> return tObj;

>};

Здесь CError класс исключения. Или втыкаем статический экземпляр-шпион.

>private:

> T* tObj; // Это было;

> static T* spy; // Это добавлено

Ну и сам перегруженный оператор.

>T* operator-›() >{

> if (!tObj) return spy;

> return tObj;

>};

Здесь нужно пояснить: spy совсем не обязательно класса T. Можно воткнуть производный, и переопределить его функции. Тогда он будет Вам докладывать о попытках обращения к NULL. Не забудьте его создать, инициализировать, и прицепить к указателю. А то вся идея на помойку. Вы пытаетесь отловить обращение к NULL, а там… NULL!!! "Матрицу" видели?

2. Отладка и трассировка.

Ну это совсем банально. Выносим определение операторов за определение класса и ставим там точку останова. Чтобы не тормозило в релиз версии, окружаем слово inline ифдефами.

>template ‹class T›

>#ifndef DEBUG

>inline

>#endif

>SmartPointer‹T›::operator T*() >{

> return tObj;

>}


>template ‹class T›

>#ifndef DEBUG

>inline

>#endif

>T* SmartPointer‹T›::operator T-›() >{

> return tObj;

>}

3. Статистика классов и объектов.

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

4. Кэширование.

Здесь сложнее. Об этом мне самому нужно почитать и полапать руками. Идея, как можно догадаться, в том, что если при обращении к умному указателю объект отсутствует в памяти, он считывается с диска. Проблемы самые очевидные в том, когда его снова отгружать на диск, разрушать объект, и как гарантировать единичность копии объекта при наличии многих ссылок.

Так. Пока тормозим. Интересно, о чем я напишу следующий шаг?

Шаг 4 - О двойной диспетчеризации.

Предположим, у нас есть массив, в котором мы храним карту местности. Разумеется, что элементы массива разнообразные - дома, колодцы, казино… ничего общего. Кроме суперкласса - предка естественно.