> printf("saveIni\n");
>}
>void Application::Run() {
> wnd=new Window();
> //цикл обработки сообщений
> delete wnd;
>}
>Application* Application::_self=NULL;
Модуль WINDOW
>#include "app.h"
>class Window {
> int width;
> int height;
>public:
> Window() {
> Application *p=Application::Instance();
> p->loadIniInt(string("Window"), string("width"));
> p->loadIniInt(string("Window"), string("height"));
> }
> ~Window() {
> Application *p=Application::Instance();
> p->saveIniInt(string("Window"), string("width"), width);
> p->saveIniInt(string("Window"),string("height"), height);
> }
>};
Этот листинг показывает, как можно организовать каркас оконного приложения, используя паттерн Singleton. Из класса окна требуется доступ к некоторым функциям объекта Application. Поскольку объект приложения существует всегда в одном экземпляре, то он реализует паттерн Singleton, а доступ к объекту приложения из объекта окна осуществляется благодаря методу Instance().
Проблема удаления объекта “Singleton”.
В приведенной выше реализации класса Singleton, есть метод создания объекта, но отсутствует метод его удаления. Это означает, что программист должен помнить в каком месте программы объект удаляется. Другая проблема, связанная с удалением объекта из памяти, возникает при полиморфном использовании объектов класса. Рассмотрим, например, такой код.
Листинг 5
>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() для управления временем жизни объекта.
Листинг 6
>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().
Листинг 7
>class Singleton {
>protected:
> static Singleton* _self;
> static int _refcount;
> Singleton(){}