Паттерн Singleton (Одиночка)
От: Дмитрий Федоров  
Дата: 14.11.02 08:08
Оценка: 256 (11) +1
Статья:
Паттерн Singleton (Одиночка)
Автор(ы): Дмитрий Федоров
Дата: 14.11.2002


Авторы:
Дмитрий Федоров

Аннотация:
Особенностью Singleton является то, что он гарантирует существование объекта в единственном экземпляре, а самое главное, то, что он создается в тот момент, когда это требуется клиенту. Последующие попытки конструирования объекта приводят лишь к возвращению клиенту ссылки на уже существующий объект, но не к созданию нового.
Как бы так это заделать???
От: konst  
Дата: 11.12.02 16:17
Оценка:
Во первых, статья очень хорошая и полезная, спасибо. Применил в реальной программе я этот сингелтон и остался очень доволен. Но мне надо было несколько изменить поведение исходного класса. У меня ситуация такая: есть клиент, который шлёт запросы на сервер, на сервере есть класс, который создаёт и хранит необходимые для обработки этих запросов таблицы. Но беда в том, что после обработки очередного запроса мне не надо уничтожать объект, т.к. эти запросы идут сериями по многу штук подряд, а удалять объект надо в конце серии... Я сделал во что:

template <class T>
T*  Singleton<T>::Instance()
{
  if(!_self)
  {
    _self=new T;
    _refcount++; // вот это
  }
  _refcount++;
  return _self;
}

Но выглядит на мой взгляд коряво. Может есть какие-то паттерны на этот случай?
Ну, в довесок хочу воткнуть так вот полу-смарт указатель:

template<class T>
class TSingeltonPtr
{
  T *_t;
public:
  TSingeltonPtr() { _t = T::Instance(); }
  ~TSingeltonPtr() { if(_t) _t->FreeInst(); }
  operator T*() { return _t; }
  T* operator->() { return _t; }
  bool operator!() const { return _t==0; }
};

использование:

class Derived : public Singleton<Derived>
{
void foo();
...
};
void bar()
{
  TSingeltonPtr<Derived> sp;
  if ( !sp ) return;
  sp->foo();
}
Маленькое замечание
От: ingie Россия  
Дата: 03.12.02 13:39
Оценка:
Все таки непонятно, откуда пошла дурацкая мода в с++ коде давать данным-членам класса символ подчеркивания в качестве префикса? То есть, и так ясно откуда...
Но ведь c++ не java... Например на MCVC++ код с такими префиксами не компилируется иногда. Ведь сказано же, зарезервировано под надобности компиляторов. Или это специально так отформатировано, чтобы читать было красивее? ;)

А статья действительно хорошая, удивило то что почти не пересекается с [3] ;)
зачем возвращать указатель?
От: Sergeem Израиль  
Дата: 19.11.02 09:56
Оценка:
Еще хочу добавить: почему Instance() возвращает указатель а не ссылку? Тогда и путаницы с delete не будет!
Serge.

Hасколько проще была бы жизнь, если бы она была в исходниках.
взаимодействие синглтонов
От: Sergeem Израиль  
Дата: 19.11.02 09:52
Оценка:
Интересно обсудить эту тему.
Например у меня есть синглтон — менеджер памяти, синглтон — БД-клиент, и т.д.
Тогда менеджер памяти должен "уходить" последним, поскольку другие с-тоны могут освобождать память в своих деструкторах. Интересный вариант есть в loki. Я реалиовал свою модель. феслт кому интересно, могу поделиться или обсудить где-нить в С++ форуме.
Serge.

Hасколько проще была бы жизнь, если бы она была в исходниках.
Просто хотел высказаться, потому как наболело :)
От: the_moon  
Дата: 18.11.02 12:10
Оценка:
Я тоже тут недавно боролся с глобальными методами и классами, в итоге я отказался от глобального класса, а зделал набор интерфейсов который упрятал в namespace. Там же я определил локальные переменные и локальную instance класса switcher, который имеет только конструктор и деструктор и занимается инициализацией и уничтожением внутренних данных функционального набора при запуске-выходе из программы.

типа

myinterface.h
namespace myinterface
{

bool Start();
bool Stop();

bool DoAction();

}


myinterface.cpp
include "myinterface.h"

static struct __Switcher
{
     __Switcher() { constructor(); }
    ~__Switcher() { destructor(); }

} theSwitcher;


static int* InterfaceData;

static void constructor()
{
    InterfaceData = new int(0);
}

static void destructor()
{
    delete InterfaceData;
}

bool myinterface::Start()
{
   //здесь можно принять какието параметры из вне
   //так же можно проверить если другие неоходимые интерфесы 
   //уже запущенны, проинициализированны
}

bool myinterface::Stop()
{
   //(для примера) Мне требовалась остановка потоков без прекращения работы программы
}

bool myinterface::DoAction()
{
    printf( "Hallo from do_action [%d]", InterfaceData++ );
}


То есть мне не надо было заботится об инстансировании глобального объекта, мне почему то показалось жто важным, хотя он и присутсвует тоже.
Снимается проблема со множественным инстансированием.
Проблемы с наследованием практически нет.
Пользователь видит только то, что ему видеть пологается и предлагается.

Конечно не объектно ориентированно, но все-же.
KOPOTbILLIKA KPbIC
И еще нужны дополнения
От: Lexey Россия  
Дата: 15.11.02 08:45
Оценка:
О том, как сделать потокобезопасное создание синглтона. Причем желательно без использования объетов ядра.
Нужны некоторые дополнения
От: Anton V. Kolotaev  
Дата: 15.11.02 08:08
Оценка:
Спасибо за статью.
Однако хотелось бы отметить, что в ней не указан т.н. Meyer's Singleton.
Он более безопасно (имхо) решает проблему удаления одиночки, достаточно прозрачен в реализации, и его я в основном и использую

struct theT 
{
    static T& Instance () {
        static T self;  // здесь можно провести инициализацию связки стат. объектов.
                        // для этого удобно использовать конструктор локального
                        // класса, статическая переменная которого определяется
                        // в этом методе
        return self;
    }
};

Этот прием описан у Александреску в главе 6 Implementing Singletons
Re: Маленькое замечание
От: alexkro  
Дата: 02.03.03 05:55
Оценка:
современная мода — писать подчеркивание в конце переменных: refcount_.
Re: взаимодействие синглтонов
От: odisseyLM  
Дата: 30.01.03 12:12
Оценка:
Слушай, а ты смог ее(Loki) откомпилить в VC?
Re: взаимодействие синглтонов
От: konst  
Дата: 10.12.02 15:27
Оценка:
а выложи на исходники свой вариант
Re: зачем возвращать указатель?
От: null  
Дата: 20.11.02 12:35
Оценка:
Потому, что идея заключается в отказе от применения статических объектов.
Re: И еще нужны дополнения
От: Lostar Россия  
Дата: 17.11.02 19:13
Оценка:
Double-Checked Locking???
С уважением, Николай.
Re: Нужны некоторые дополнения
От: null  
Дата: 15.11.02 09:27
Оценка:
Я знаком с этим типом 'реализации' синглетона, однако не считаю его полноценным синглетоном с точки зрения постановки задачи в начале статьи — возможность управлять временем создания и удаления объекта. В реализации предлагаемой Meyers'ом объект все равно создается и удаляется статически, то есть те проблемы которые описаны в начале статьи статьи остаются в силе. Единственную задачу которую решает данная реализация — это гарантия того, что объект существует в единственном экземпляре, а этого не достаточно.
Re: зачем возвращать указатель?
От: Frostbitten Россия  
Дата: 10.02.03 21:03
Оценка:
А почему он вообще что-то возвращает, да еще "так"?

{
   if (Derived::Instance()->IsReadyToSetCounter())
   {
      Derived::Instance()->SetSomeCouner(
         Derived::Instance()->GetSomeCouner() +1);
   }
}

Очень наглядно... только память куда-то девается :)
Может стоит bool GetInstance(BaseT** pInst) const; ?
Meyers singleton: время создания и удаления
От: Anton V. Kolotaev  
Дата: 15.11.02 14:27
Оценка:
Объект создается при первом обращении и разрушается по выходу и программы.
Гарантируется, что чем позже объект создан, тем раньше он будет разрушен.
Из этого следует, что проблемы возникнут, если в деструкторе одиночка класса A обращается к одиночке класса В, а тот уже разрушен. Это возможно в случае, если одиночка класса В создан позже одиночки класса А... На самом деле интересно, что будет если при закрытии программы после того, как разрушен одиночка B, вызывается деструктор одиночки А, который обращается к одиночке класса В. Будет ли создан заново экземпляр класса В или произойдет сбой?
Re[2]: зачем возвращать указатель?
От: StanislavK Великобритания  
Дата: 28.07.03 08:07
Оценка:
Здравствуйте, null, Вы писали:

N>Потому, что идея заключается в отказе от применения статических объектов.

Какая связь между ссылкой и статическим объектом?
Singleton не должен ни при каких условиях возвращать указатель, дабы не было никаких соблазнов и ошибок.
... << RSDN@Home 1.1 beta 1 >>
Re[2]: Нужны некоторые дополнения
От: Павел Кузнецов  
Дата: 28.07.03 08:56
Оценка:
Здравствуйте, null, Вы писали:

n> Единственную задачу которую решает данная реализация — это гарантия того,

n> что объект существует в единственном экземпляре,

Даже эту задачу данная реализация успешно решает только при условии отсутствия
многопоточности. В это решение корректно синхронизацию добавить весьма проблематично.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: Паттерн Singleton (Одиночка)
От: Евгений Коробко  
Дата: 03.12.03 11:38
Оценка:
Здравствуйте, Дмитрий Федоров, Вы писали:

Ещё одно дополнение. Для singleton нужно переопределять операторы присваивания и конструктор копирования. Наиболее разумная реакция, на мой взгляд, — генерация исключения. Тогда и проблем с

Singleton s=*Singleton.Instance()

не будет.
Евгений Коробко
Re[2]: Паттерн Singleton (Одиночка)
От: schakal Украина kp.datax.com.ua
Дата: 03.12.03 12:15
Оценка: +2
Ну какая ж это разумная реализация?
Закрытыми их надо делать...


"Евгений Коробко" <12408@news.rsdn.ru> wrote in message news:466069@news.rsdn.ru...
> Здравствуйте, Дмитрий Федоров, Вы писали:
>
> Ещё одно дополнение. Для singleton нужно переопределять операторы присваивания и конструктор копирования. Наиболее разумная реакция, на мой взгляд, — генерация исключения. Тогда и проблем с
>
> Singleton s=*Singleton.Instance()
>
> не будет.
Posted via RSDN NNTP Server 1.8 beta
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.