Примеры использования Паттерн Singleton (Одиночка) - [2]
В приведенной выше реализации класса Singleton, есть метод создания объекта, но отсутствует метод его удаления. Это означает, что программист должен помнить в каком месте программы объект удаляется. Другая проблема, связанная с удалением объекта из памяти, возникает при полиморфном использовании объектов класса. Рассмотрим, например, такой код.
>class Client {
> Singleton * _pS;
>public:
> SetObject(Singleton *p) {_pS=p;}
> ~Client(){delete _pS;}
>};
>void main() {
> Client c1,c2;
> c1.SetObject(Singleton::Instance());
> c2.SetObject(Singleton::Instance());
>}
Эта программа будет пытаться удалить дважды один и тот же объект, что приведет к исключительной ситуации в программе. При выходе из контекста функции main, сначала будет вызван деструктор объекта c2, который удалит объект класса Singleton, а затем то же самое попытается сделать и деструктор объекта c1. В связи с этим, хотелось бы иметь механизм, позволяющий автоматически отслеживать ссылки на объект класса Singleton, и автоматически удалять его только тогда, когда на объект нет активных ссылок. Для этого используют специальный метод FreeInst(), удаляющий объект только в случае, если активных ссылок на него нет.
Другая задача, которую надо решить – запрет удаления клиентом объекта Singleton посредством оператора delete. Это решается помещением деструктора в секцию protected.Тем самым, клиенту ничего не остается, как использовать пару Instance()/FreeInst() для управления временем жизни объекта.
>class Singleton {
>protected:
> static Singleton* _self;
> static int _refcount;
> Singleton(){};
> ~Singleton(){};
>public:
> static Singleton* Instance();
> void FreeInst() {_refcount--; if(!_refcount) {delete this; _self=NULL;}}
>};
В данном примере, в класс Singleton введен счетчик ссылок. Метод FreeInst() вызывает оператор удаления только тогда, когда _refcount равен нулю.
Проблема наследования
Если существует необходимость наследовать от класса Singleton, то следует придерживаться определенных правил.
Во-первых, класс-наследник должен переопределить метод Instance(), так, чтобы создавать экземпляр производного класса. Если не предполагается, что указатель будет использоваться полиморфно, то можно объявить возвращаемый тип метода Instance() как указатель на класс-наследник, в противном случае, метод Instance() должен возвращать указатель на базовый класс (Singleton).
Во-вторых, в базовом классе деструктор должен быть объявлен как виртуальный: в определенный момент клиент вызывает метод FreeInst для указателя на базовый класс. Поскольку метод FreeInst сводится к оператору delete this, то в случае, если деструктор не виртуальный, будет вызван деструктор базового класса, но не будет вызван деструктор класса-потомка. Чтобы избежать такой ситуации, следует явно объявить деструктор базового класса виртуальным.
В-третьих, конструктор класса-потомка также должен быть объявлен в защищенной секции, чтобы избежать возможности создания объекта класса напрямую, минуя метод Instance().
>class Singleton {
>protected:
> static Singleton* _self;
> static int _refcount;
> Singleton(){}
> virtual ~Singleton() {printf ("~Singleton\n");}
>public:
> static Singleton* Instance();
> void FreeInst();
>};
>class SinglImpl: public Singleton {
>protected:
> SinglImpl(){}
>//объявление виртуальным в базовом классе автоматически
> //дает виртуальность в производном.
> ~SinglImpl() {printf ("~SinglImpl\n");}
>public:
> static Singleton* Instance() {
> if(!_self) _self = new SinglImpl();
> _refcount++;
> return _self;
> }
>};
>void main() {
> Singleton *p = SinglImpl::Instance();
> …
> …
> …
> p->FreeInst();
>}
Результат работы:
~SinglImpl
~Singleton
Иногда может возникнуть ситуация, при которой клиент должен полиморфно работать с объектами, имеющими общий базовый класс, но некоторые из них реализуют паттерн Singleton, а некоторые нет. Проблема возникает в момент освобождения объектов, так как у простых классов нет механизма отслеживания ссылок, а у классов, реализующих Singleton, он есть. При вызове метода FreeInst() через указатель на базовый класс будет вызываться FreeInst() базового класса, не имеющего понятия о подсчете ссылок. Это приведет и к безусловному удалению объектов “Singleton” из памяти. Для предотвращения такого поведения следует объявить виртуальным метод FreeInst() в базовом классе и реализовать специфическое поведение метода для классов Singleton. Реализация FreeInst() в базовом классе предоставляет механизм удаления объектов, не являющихся Singleton’ами.
>class base {
>protected:
> virtual ~base(){}
> //гарантируем удаление только через FreeInst()
>public:
> virtual void Do1()=0;
> virtual void FreeInst(){delete this;}
>};
>class Simple: public base {
>protected:
> ~Simple () {printf("Simple::~Simple\n");}
>public:
> void Do1(){printf("Simple::Do1\n");}
>};
>class Singleton: public base {
> static Singleton* _self;
> static int _refcount;
>protected:
> Singleton(){}
> ~Singleton () {printf("Singleton::~Singleton\n");}
>public:
> static Singleton* Instance() {
> if(!_self) _self = new Singleton ();
> _refcount++;
> return _self;
> }
> void FreeInst() {_refcount--; if(!_refcount) {delete this; _self=NULL;}}
![Виктор Тихонов. Жизнь во имя хоккея](/storage/book-covers/d3/d30f22d3ee1dee1fff9ee0d3b89b9a250fbbd328.jpg)
Виктор Васильевич Тихонов – легенда советского и российского хоккея. В качестве главного тренера сборной он трижды добился с командой золотых медалей на Олимпиадах, восемь раз его команда завоевала титул чемпиона мира, а команда ЦСКА двенадцать раз становилась чемпионом СССР. Каким он был, «Мистер Дисциплина»? Как ему удалось добиться с командой таких успехов? Ответы на эти вопросы – в его дневниках и воспоминаниях супруги, Татьяны Васильевны, а также – в фотографиях из их личного архива.
![Загольная жизнь](/build/oblozhka.dc6e36b8.jpg)
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
![Отдыхай с Гусом Хиддинком: четыре анекдотичные футболяшки](/storage/book-covers/ee/ee656a2d476f287a21641e5e1ac83cb8c6ed7dc4.jpg)
«Отдыхай с Гусом Хиддинком» – четыре нереально смешные фантастические истории, герои которых существуют в каком-то странном пространстве – то ли виртуальном, то ли со смещенным временем, то ли вообще в мире галлюцинаций. В День национального единства русские гении – Пушкин, Достоевский и другие – играют против Рональдинью, Джеррарда, Анри и прочих звезд мира.Со школы знакомые картины, вроде «Грачи прилетели», становятся фанатскими баннерами, а Гоголь переделывает бессмертного «Резизора» под актуальные футбольные нужды.Руководство «Спартака» придумывает радикальный пиар-ход, чтобы стать ближе к народу.
![Удар из галактики](/build/oblozhka.dc6e36b8.jpg)
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
![Трансфер гастарбайтера](/build/oblozhka.dc6e36b8.jpg)
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
![Спартакобрядцы](/build/oblozhka.dc6e36b8.jpg)
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
![Графика для Windows средствами DirectDraw](/storage/book-covers/6d/6dbc78361f37e9af5b71d5019ca64570a40e0466.jpg)
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
![Виртуальная библиотека Delphi](/build/oblozhka.dc6e36b8.jpg)
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
![Пишем драйвер Windows на ассемблере](/build/oblozhka.dc6e36b8.jpg)
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
![Как писать драйвера](/build/oblozhka.dc6e36b8.jpg)
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
![MFC и OpenGL](/build/oblozhka.dc6e36b8.jpg)
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
![Информационная технология. Оценка программной продукции характеристики качества и руководства по их применению](/build/oblozhka.dc6e36b8.jpg)
Стандарт подготовлен на основе применения аутентичного текста международного стандарта ИСО/МЭК 9126-91 «Информационная технология. Оценка программной продукции. Характеристики качества и руководства по их применению»Information technology. Software product evaluation. Quality characteristics and guidelines for their use.