Re[2]: Паттерн Singleton (Одиночка)
От: PM  
Дата: 03.12.03 12:28
Оценка:
Здраствуйте, Евгений Коробко. Вы писали:

ЕК> Ещё одно дополнение. Для singleton нужно переопределять операторы

ЕК> присваивания и конструктор копирования. Наиболее разумная реакция, на
ЕК> мой взгляд, — генерация исключения. Тогда и проблем с
ЕК>
ЕК> Singleton s=*Singleton.Instance()
ЕК>
ЕК> не будет.
А зачем кидаться исключениями, если можно запретить копирование и присваивание на этапе компиляции?

ps. Странно, что не видел этой статьи раньше
Posted via RSDN NNTP Server 1.7 "Bedlam"
Re[3]: От модератора форума C/C++
От: Павел Кузнецов  
Дата: 03.12.03 12:35
Оценка:
Здравствуйте, schakal, Вы писали:

s> Ну какая ж это разумная реализация?

s> Закрытыми их надо делать...

s> "Евгений Коробко" <12408@news.rsdn.ru> wrote in message news:466069@news.rsdn.ru...

>> Здравствуйте, Дмитрий Федоров, Вы писали:
>>
>> <...>

Ваше сообщение нарушает правила форумов RSDN в отношении оформления и объема цитирования.

Подобный стиль цитирования, т.е. набор нового текста в начале сообщения с последующим
цитированием всего текста оригинального сообщения (top posting) не приветствуется в форумах
RSDN.ru, более того, настоятельно рекомендую не допускать этого в дальнейшем, так как:

Q: Because it reverses the logical flow of conversation.
A: Why is top posting frowned upon?


Ваши читатели будут вам благодарны, если в дальнейшем вы будете цитировать из исходного
сообщения ровно столько, сколько необходимо для понимания контекста вашего ответа, а также
размещать строки своего ответа непосредственно под цитируемыми фрагментами, соответственно
разбивая исходное сообщение. Также считаю нужным обратить ваше внимание на то, что в форумах
RSDN.ru рекомендуется оформлять цитаты, помещая аббревиатуру автора оригинального сообщения
перед символом '>' в начале каждой цитируемой строки.

Плагин для Outlook Express, с легкостью позволяющий это делать, вы можете найти здесь:
http://www.fidolook.com

Более подробно о настройке NNTP клиента для работы с форумами РСДН:
http://www.rsdn.ru/files/progs/rsdnnntp/rsdnnntp.xml

Может быть, лично вам по каким-либо причинам более удобен формат, использованный вами
в своем ответе; также вполне возможно, что вы можете не соглашаться с соображениями,
изложенными выше. Тем не менее, обращаю ваше внимание, что предлагаемый формат сообщений
является именно тем, что предпочитает большинство активных пользователей RSDN.ru, и,
соответственно, тем, чего они ожидают для комфортного чтения. Следуя принятым здесь
обычаям, вы скорее встретите доброжелательно настроенных собеседников, готовых помочь
и пойти навстречу.

Спасибо.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: Паттерн Singleton (Одиночка)
От: Кодт Россия  
Дата: 03.12.03 15:40
Оценка: 3 (2)
Здравствуйте, Дмитрий Федоров, Вы писали:

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


С рождением и смертью синглетона не все так однозначно.

Синглетон создается при первом обращении, затем погибает
— по обнулению ссылок
— по "свистку" (например, по завершению модуля)
После свистка он может быть пересоздан, либо запрещен.

Свисток — это либо выход из программы (код завершения в CRT), либо ручная отмашка.
По ряду причин синглетоны, живущие в DLL, нужно убивать из DllMain(DLL_PROCESS_DETACH), а не из DLL'ского CRT.
Александреску регистрирует функции-убийцы синглетона в atexit(), я предпочитаю определять у синглетона открытый метод-убийцу или делать аналог atexit() с ручным вызовом всей коллекции в DllMain.
typedef void(*my_atexit_fn)(void*);

void schedule_my_atexit(my_atexit_fn fn, void* param); // добавляет функцию в начало списка
void perform_my_atexit(); // вызывает все, что было спланировано



Чтобы не возиться с подсчетом ссылок вручную, указатели на синглетон должны быть умными. Например, так:
template<class T>
class single_holder
{
  friend class single_ptr<T>;

  void addref();
  void release();
  T* take();
  ... all implementation ...
public:
  static single_ptr instance() { return single_ptr(); } // этот метод - дань стилю
};

template<class T>
class single_ptr
{
  typedef single_holder<T> holder;
public:
  single_ptr() { return holder::addref(); }
  single_ptr(const single_ptr&) { return holder::addref(); }
  ~single_ptr() { return holder::release(); }

  operator T*() const { return holder::take(); }
  T* operator->() const { return holder::take(); }
};



Конструкторы (без параметров и копирования) и деструктор синглетона имеет смысл закрывать.
Чтобы single_holder мог работать, нужно объявить его другом.
Конструктор копирования вообще не существует — его объявляют, но не определяют.
class my_single
{
  friend class single_holder<my_single>;

  my_single(const my_single&);

protected: // если допускаем существование наследников
  my_single() { . . . }
  ~my_single() { . . . }

public:
  . . .
};
Перекуём баги на фичи!
Re[2]: Паттерн Singleton (Одиночка)
От: GarikTot  
Дата: 03.12.03 16:22
Оценка:
Здравствуйте, Кодт, Вы писали:

К>По ряду причин синглетоны, живущие в DLL, нужно убивать из DllMain(DLL_PROCESS_DETACH), а не из DLL'ского CRT.

К>Александреску регистрирует функции-убийцы синглетона в atexit(), я предпочитаю определять у синглетона открытый метод-убийцу или делать аналог atexit() с ручным вызовом всей коллекции в DllMain.

Можно об этом подробнее?

К>Конструкторы (без параметров и копирования) и деструктор синглетона имеет смысл закрывать.

К>Чтобы single_holder мог работать, нужно объявить его другом.
К>Конструктор копирования вообще не существует — его объявляют, но не определяют.
К>
К>class my_single
К>{
К>  friend class single_holder<my_single>;

К>  my_single(const my_single&);

К>protected: // если допускаем существование наследников
К>  my_single() { . . . }
К>  ~my_single() { . . . }

К>public:
К>  . . .
К>};
К>


И примерчик использования всего этого хозяйства?

Удалено избыточное цитирование. -- ПК.
Re: Паттерн Singleton (Одиночка)
От: magistr  
Дата: 24.12.04 08:48
Оценка:
Здравствуйте!
У меня такой вот вопрос:
1. Вот тут все говорят, что это плохой сингетон. Где мжно посмотреть на хороший?
2. Как сделать так, чтобы можно было делать наследования такого рода:


class Object:public Singleton<Object>
{
..
private:
   virtual void OnCreate();
..
}


//теперь наследование от класса Object:
class MyObject:public Object
{
..
private:
   MyObject(){}
   virtual void OnCreate()
   {
      MessageBeep(1);
   }
..
}
//проверяем:
MyObject *obj=(MyObject*)MyObject::Instance();
obj->OnCreate(); //не заходит в MyObject


Как сделать так, чтобы можно было так делать?
Я то понимаю, что одиночка был создан ещё при инициализации Object...
Re[2]: Нужны некоторые дополнения
От: Andrew S Россия http://alchemy-lab.com
Дата: 24.12.04 11:34
Оценка:
N>Я знаком с этим типом 'реализации' синглетона, однако не считаю его полноценным синглетоном с точки зрения постановки задачи в начале статьи — возможность управлять временем создания и удаления объекта. В реализации предлагаемой Meyers'ом объект все равно создается и удаляется статически, то есть те проблемы которые описаны в начале статьи статьи остаются в силе.
Ответ неверный.
N>Единственную задачу которую решает данная реализация — это гарантия того, что объект существует в единственном экземпляре, а этого не достаточно.
Аналогично.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[3]: Нужны некоторые дополнения
От: Andrew S Россия http://alchemy-lab.com
Дата: 24.12.04 11:35
Оценка:
n>> Единственную задачу которую решает данная реализация — это гарантия того,
n>> что объект существует в единственном экземпляре,

ПК>Даже эту задачу данная реализация успешно решает только при условии отсутствия

ПК>многопоточности. В это решение корректно синхронизацию добавить весьма проблематично.

Согласен, что синхронизация тут довольно проблематична, впрочем, как и в любом синглтоне. Но решить ее можно, и в соотв. топике форума С++ варинты решений приводились.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[2]: Паттерн Singleton (Одиночка)
От: Аноним  
Дата: 21.03.05 11:04
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Свисток — это либо выход из программы (код завершения в CRT), либо ручная отмашка.

К>По ряду причин синглетоны, живущие в DLL, нужно убивать из DllMain(DLL_PROCESS_DETACH), а не из DLL'ского CRT.
К>Александреску регистрирует функции-убийцы синглетона в atexit(), я предпочитаю определять у синглетона открытый метод-убийцу или делать аналог atexit() с ручным вызовом всей коллекции в DllMain.
К>
К>typedef void(*my_atexit_fn)(void*);

К>void schedule_my_atexit(my_atexit_fn fn, void* param); // добавляет функцию в начало списка
К>void perform_my_atexit(); // вызывает все, что было спланировано
К>


А можно глянуть, как выполняется вызов "всей коллекции в DllMain"? Каждый раз при использовании синглетона в DLL нужно не забыть и вставить цикл в DllMain? А для забывчивых есть какое нибудь средство?
Re: Meyers singleton: время создания и удаления
От: BlackHeretic Израиль  
Дата: 31.03.05 11:07
Оценка:
Здравствуйте, Anton V. Kolotaev, Вы писали:

AVK>Объект создается при первом обращении и разрушается по выходу и программы.

AVK>Гарантируется, что чем позже объект создан, тем раньше он будет разрушен.
AVK>Из этого следует, что проблемы возникнут, если в деструкторе одиночка класса A обращается к одиночке класса В, а тот уже разрушен. Это возможно в случае, если одиночка класса В создан позже одиночки класса А... На самом деле интересно, что будет если при закрытии программы после того, как разрушен одиночка B, вызывается деструктор одиночки А, который обращается к одиночке класса В. Будет ли создан заново экземпляр класса В или произойдет сбой?

Однозначно сбой — такие переменные по определению создаются один раз и повторно созданы не будут.
ICQ 156156278
Re: Паттерн Singleton (Одиночка)
От: ansi  
Дата: 02.04.05 13:16
Оценка: 3 (1)
Статья понравилась. Только есть одно замечание — есть там следующий код:
class SinglImpl: public Singleton
{
protected:
  SinglImpl(){}
  //объявление виртуальным в базовом классе автоматически 
  //дает виртуальность в производном.
  ~SinglImpl() { printf ("~SinglImpl\n"); }
public:
  static Singleton* Instance()
  {
    if(!_self) _self = new SinglImpl();
    _refcount++;
    return _self;
  }
};


Так вот, почему бы вместо двух строк комментария не поставить одно(!) слово virtual? Так на мой взгляд и нагляднее, и понятнее, и копаться в родителях нет надобности (если их много будет)...

Ну и про подчеркивания уже говорили. Я понимаю, что это собственный стиль и каждый его выбирает сам, но он затрудняет чтение, так как человек распознаёт слово целиком, а "_" этому мешает. В данной статье он употреблен грамотно, без злоупотреблений. Но это потому, что членов класса было не много. А вообще, для сравнения:

template <class _Key, class _Value, class _KeyOfValue, 
          class _Compare, class _Alloc> void 
_Rb_tree<_Key,_Value,_KeyOfValue,
  _Compare,_Alloc>::_M_erase(_Rb_tree_node<_Value>* __x)
{
                                // erase without rebalancing
  while (__x != 0) {
    _M_erase(_S_right(__x));
    _Link_type __y = _S_left(__x);
    _Destroy(&__x->_M_value_field);
    this->_M_header.deallocate(__x,1);
    __x = __y;
  }
}


template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
void RbTree <Key, Value, KeyOfValue, Compare, Alloc> :: Erase(RbTreeNode<Value>* x)
{
                                // erase without rebalancing
  while (x != 0) {
    
    Erase( Right(x) );

    LinkType y = Left(x);
    Destroy( &x->ValueField );
        
    this->Header.deallocate(x, 1);

    x = y;

  }
}
new RSDN@Home(1.1.4, 303) << new Message(); std::head::ear << "Celtic Angels — Angels Sea";
Re[2]: Паттерн Singleton (Одиночка)
От: Raurat_Ltd Россия http://cyclone-soft.com
Дата: 02.04.05 16:53
Оценка: :)
Hello, ansi!
You wrote on Sat, 02 Apr 2005 13:16:09 GMT:

a> Ну и про подчеркивания уже говорили. Я понимаю, что это собственный

a> стиль и каждый его выбирает сам, но он затрудняет чтение, так как
a> человек распознаёт слово целиком, а "_" этому мешает. В данной статье он
a> употреблен грамотно, без злоупотреблений. Но это потому, что членов
a> класса было не много. А вообще, для сравнения:

a>
 a> template <class _Key, class _Value, class _KeyOfValue, 
 a>           class _Compare, class _Alloc> void 
 a> _Rb_tree<_Key,_Value,_KeyOfValue,
 a>   _Compare,_Alloc>::_M_erase(_Rb_tree_node<_Value>* __x)
 a> {
 a>                                 // erase without rebalancing
 a>   while (__x != 0) {
 a>     _M_erase(_S_right(__x));
 a>     _Link_type __y = _S_left(__x);
 a>     _Destroy(&__x->_M_value_field);
 a>     this->_M_header.deallocate(__x,1);
 a>     __x = __y;
 a>   }
 a> }
 a>


a> [ccode]

a> template <class Key, class Value, class KeyOfValue, class Compare, class
a> Alloc> void RbTree <Key, Value, KeyOfValue, Compare, Alloc> ::
a> Erase(RbTreeNode<Value>* x) {
a> // erase without rebalancing
a> while (x != 0) {

a> Erase( Right(x) );


a> LinkType y = Left(x);

a> Destroy( &x->ValueField );

a> this->Header.deallocate(x, 1);


a> x = y;


Во блин, это оказвается стиль такой. Я то думал, что разработчики STL в Майкрософте специально так код изгадили, чтобы его читать было нельзя.


With best regards, Alexander. E-mail: fastbrain@hotbox.ru
Posted via RSDN NNTP Server 1.9
Re[3]: Паттерн Singleton (Одиночка)
От: Костя Ещенко Россия  
Дата: 03.04.05 02:35
Оценка:
Raurat_Ltd wrote:

> Во блин, это оказвается стиль такой. Я то думал, что разработчики STL в Майкрософте специально так код изгадили, чтобы его читать было нельзя.


Его изгадили не просто так, а со смыслом. Имена начинающиеся с 2х знаков подчеркивания (__x) или со знака подчеркивания и заглавной буквы (_Key) зарезервированы для использования реализацией стандартной библиотеки во всех контекстах.
Если бы они не использовали зарезервированные имена, то существовала бы вероятность, что некоторое имя из реализации стандартной библиотекии совпадет например с именем пользовательского макроса, и привет.
Posted via RSDN NNTP Server 1.9
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re: Паттерн Singleton (Одиночка)
От: Daimond Россия  
Дата: 02.08.05 12:23
Оценка:
Здравствуйте, Дмитрий Федоров, Вы писали:

Спасибо за статью. Понравилась.

Но вопорс возник.

Раздел "Применение шаблонов языка C++"
Там есть такой код (приведу полностью, для понятности):


template <class T>
class Singleton
{
  static T* _self;
  static int _refcount;
protected:
  Singleton(){}
  virtual ~Singleton(){_self=NULL;} // Здесь _self не удаляется
public:
  static T* Instance();
  void FreeInst();
};

template <class T>
T*  Singleton<T>::_self = NULL;

template <class T>
int  Singleton<T>::_refcount=0;

template <class T>
T*  Singleton<T>::Instance()
{
  if(!_self)
    _self=new T;  // Здесь создается объект типа T
  _refcount++;
  return _self;
}

template <class T>
void  Singleton<T>::FreeInst()
{
  if(--_refcount==0)
    delete this;  
    //Почему delete this; ? создавался ведь объект типа T. На мой взгляд delete _self нужно;

}
Re[2]: Паттерн Singleton (Одиночка)
От: Left2 Украина  
Дата: 02.08.05 13:10
Оценка:
[code]
virtual ~Singleton()
[/ccode]

Деструктор виртуальный, значит никаких проблем при удадении по указателю на базовый класс.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re: Паттерн Singleton (Одиночка)
От: k. Россия  
Дата: 02.08.05 15:10
Оценка:
не совсем согласен с подобным удалением синглтона. atexit мне кажется более привлекательной.
... << RSDN@Home 1.1.3 stable >>
Re: Паттерн Singleton (Одиночка)
От: LeeMouse Россия  
Дата: 02.08.05 19:27
Оценка: +1 -1
Здравствуйте, Дмитрий Федоров, Вы писали:

ДФ>Статья:

ДФ>Паттерн Singleton (Одиночка)
Автор(ы): Дмитрий Федоров
Дата: 14.11.2002


ДФ>Авторы:

ДФ> Дмитрий Федоров

ДФ>Аннотация:

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

Описанная задача исчерпывающе решена очень давно в библиотеке Loki от Андрея Александреску.
При внимательном изучении обоих решений очевидно, что уважаемым автором статьи проделана бесполезная работа
Re: Паттерн Singleton (Одиночка)
От: KBH  
Дата: 03.12.05 13:20
Оценка: :)
Здрасте.

Товарищи, а почему никто не предложил использовать std::auto_ptr для удаления одиночки?

#include <memory>

class Singleton {
private:
  static std::auto_ptr<Singleton> instance;

public:
  static Singleton* getInstance();

};


реализация:

#include "Singleton.h"

std::auto_ptr<Singleton> Singleton::instance; // Инициализируется нулем

Singleton* Singleton::getInstance() {
  if( !instance.get() ) {
    instance = std::auto_ptr<Singleton>(new Singleton());
  }
  return instance.get();
}


Вот и все, теперь при первом обращении создается экземпляр одиночки и уничтожается только при завершении программы.
Re[2]: Паттерн Singleton (Одиночка)
От: Аноним  
Дата: 09.07.07 16:28
Оценка:
Здравствуйте, Кодт, Вы писали:


У кого-нибудь есть рабочий вариант подхода предложеный Кодтом? Мой (который ниже) не компилируется. Поправьте меня или помогите.
template<typename T> class single_ptr;

template<class T> class single_holder {
private:
    static T* _self;
    static int _refcount;
    friend class single_ptr<T>;

    void addref()  {_refcount++;}
    void release();
    T* take();
public:
    //static single_ptr instance() { return single_ptr(); } /*А ЧТО ЗДЕСЬ???*/
};

template<class T> T* single_holder<T>::_self = 0;
template<class T> int single_holder<T>::_refcount = 0;

template<class T>
T* single_holder<T>::take() {
    if(!_self) {
        _self = new T;
    }
    return _self;
}

template<class T>
void single_holder<T>::release() {
    if(--_refcount == 0) {
        delete _self;
    }
}

template<class T>
class single_ptr
{
  typedef single_holder<T> holder;
public:
  single_ptr() { holder::addref(); }
  single_ptr(const single_ptr&) { holder::addref(); }
  ~single_ptr() { holder::release(); }

  operator T*() const { return holder::take(); }
  T* operator->() const { return holder::take(); }
};
Re: Meyers singleton: время создания и удаления
От: superman  
Дата: 12.07.07 07:58
Оценка:
Здравствуйте, Anton V. Kolotaev, Вы писали:

AVK>Объект создается при первом обращении и разрушается по выходу и программы.

AVK>Гарантируется, что чем позже объект создан, тем раньше он будет разрушен.

да ну? и кем же это гарантируется интересно.
Re[2]: Meyers singleton: время создания и удаления
От: Аноним  
Дата: 13.10.08 15:15
Оценка:
Здравствуйте, superman, Вы писали:

S>Здравствуйте, Anton V. Kolotaev, Вы писали:


AVK>>Объект создается при первом обращении и разрушается по выходу и программы.

AVK>>Гарантируется, что чем позже объект создан, тем раньше он будет разрушен.

S>да ну? и кем же это гарантируется интересно.

Стандартом C++.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.