Аннотация:
Особенностью Singleton является то, что он гарантирует существование объекта в единственном экземпляре, а самое главное, то, что он создается в тот момент, когда это требуется клиенту. Последующие попытки конструирования объекта приводят лишь к возвращению клиенту ссылки на уже существующий объект, но не к созданию нового.
Во первых, статья очень хорошая и полезная, спасибо. Применил в реальной программе я этот сингелтон и остался очень доволен. Но мне надо было несколько изменить поведение исходного класса. У меня ситуация такая: есть клиент, который шлёт запросы на сервер, на сервере есть класс, который создаёт и хранит необходимые для обработки этих запросов таблицы. Но беда в том, что после обработки очередного запроса мне не надо уничтожать объект, т.к. эти запросы идут сериями по многу штук подряд, а удалять объект надо в конце серии... Я сделал во что:
template <class T>
T* Singleton<T>::Instance()
{
if(!_self)
{
_self=new T;
_refcount++; // вот это
}
_refcount++;
return _self;
}
Но выглядит на мой взгляд коряво. Может есть какие-то паттерны на этот случай?
Ну, в довесок хочу воткнуть так вот полу-смарт указатель:
Все таки непонятно, откуда пошла дурацкая мода в с++ коде давать данным-членам класса символ подчеркивания в качестве префикса? То есть, и так ясно откуда...
Но ведь c++ не java... Например на MCVC++ код с такими префиксами не компилируется иногда. Ведь сказано же, зарезервировано под надобности компиляторов. Или это специально так отформатировано, чтобы читать было красивее? ;)
А статья действительно хорошая, удивило то что почти не пересекается с [3] ;)
Интересно обсудить эту тему.
Например у меня есть синглтон — менеджер памяти, синглтон — БД-клиент, и т.д.
Тогда менеджер памяти должен "уходить" последним, поскольку другие с-тоны могут освобождать память в своих деструкторах. Интересный вариант есть в loki. Я реалиовал свою модель. феслт кому интересно, могу поделиться или обсудить где-нить в С++ форуме.
Serge.
Hасколько проще была бы жизнь, если бы она была в исходниках.
Я тоже тут недавно боролся с глобальными методами и классами, в итоге я отказался от глобального класса, а зделал набор интерфейсов который упрятал в namespace. Там же я определил локальные переменные и локальную instance класса switcher, который имеет только конструктор и деструктор и занимается инициализацией и уничтожением внутренних данных функционального набора при запуске-выходе из программы.
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++ );
}
То есть мне не надо было заботится об инстансировании глобального объекта, мне почему то показалось жто важным, хотя он и присутсвует тоже.
Снимается проблема со множественным инстансированием.
Проблемы с наследованием практически нет.
Пользователь видит только то, что ему видеть пологается и предлагается.
Спасибо за статью.
Однако хотелось бы отметить, что в ней не указан т.н. Meyer's Singleton.
Он более безопасно (имхо) решает проблему удаления одиночки, достаточно прозрачен в реализации, и его я в основном и использую
struct theT
{
static T& Instance () {
static T self; // здесь можно провести инициализацию связки стат. объектов.
// для этого удобно использовать конструктор локального
// класса, статическая переменная которого определяется
// в этом методеreturn self;
}
};
Этот прием описан у Александреску в главе 6 Implementing Singletons
Я знаком с этим типом 'реализации' синглетона, однако не считаю его полноценным синглетоном с точки зрения постановки задачи в начале статьи — возможность управлять временем создания и удаления объекта. В реализации предлагаемой Meyers'ом объект все равно создается и удаляется статически, то есть те проблемы которые описаны в начале статьи статьи остаются в силе. Единственную задачу которую решает данная реализация — это гарантия того, что объект существует в единственном экземпляре, а этого не достаточно.
Объект создается при первом обращении и разрушается по выходу и программы.
Гарантируется, что чем позже объект создан, тем раньше он будет разрушен.
Из этого следует, что проблемы возникнут, если в деструкторе одиночка класса A обращается к одиночке класса В, а тот уже разрушен. Это возможно в случае, если одиночка класса В создан позже одиночки класса А... На самом деле интересно, что будет если при закрытии программы после того, как разрушен одиночка B, вызывается деструктор одиночки А, который обращается к одиночке класса В. Будет ли создан заново экземпляр класса В или произойдет сбой?
Здравствуйте, null, Вы писали:
N>Потому, что идея заключается в отказе от применения статических объектов.
Какая связь между ссылкой и статическим объектом?
Singleton не должен ни при каких условиях возвращать указатель, дабы не было никаких соблазнов и ошибок.
Здравствуйте, null, Вы писали:
n> Единственную задачу которую решает данная реализация — это гарантия того, n> что объект существует в единственном экземпляре,
Даже эту задачу данная реализация успешно решает только при условии отсутствия
многопоточности. В это решение корректно синхронизацию добавить весьма проблематично.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Ещё одно дополнение. Для singleton нужно переопределять операторы присваивания и конструктор копирования. Наиболее разумная реакция, на мой взгляд, — генерация исключения. Тогда и проблем с
Ну какая ж это разумная реализация?
Закрытыми их надо делать...
"Евгений Коробко" <12408@news.rsdn.ru> wrote in message news:466069@news.rsdn.ru... > Здравствуйте, Дмитрий Федоров, Вы писали: > > Ещё одно дополнение. Для singleton нужно переопределять операторы присваивания и конструктор копирования. Наиболее разумная реакция, на мой взгляд, — генерация исключения. Тогда и проблем с > > Singleton s=*Singleton.Instance() > > не будет.
Здраствуйте, Евгений Коробко. Вы писали:
ЕК> Ещё одно дополнение. Для singleton нужно переопределять операторы ЕК> присваивания и конструктор копирования. Наиболее разумная реакция, на ЕК> мой взгляд, — генерация исключения. Тогда и проблем с ЕК> ЕК> Singleton s=*Singleton.Instance() ЕК> ЕК> не будет.
А зачем кидаться исключениями, если можно запретить копирование и присваивание на этапе компиляции?
Здравствуйте, schakal, Вы писали:
s> Ну какая ж это разумная реализация? s> Закрытыми их надо делать...
s> "Евгений Коробко" <12408@news.rsdn.ru> wrote in message news:466069@news.rsdn.ru... >> Здравствуйте, Дмитрий Федоров, Вы писали: >> >> <...>
Ваше сообщение нарушает правила форумов RSDN в отношении оформления и объема цитирования.
Подобный стиль цитирования, т.е. набор нового текста в начале сообщения с последующим
цитированием всего текста оригинального сообщения (top posting) не приветствуется в форумах
RSDN.ru, более того, настоятельно рекомендую не допускать этого в дальнейшем, так как:
при таком стиле цитирования, читая набранное вверху сообщения, сложно понять,
к какой части оригинального сообщения это относится;
такой подход стимулирует избыточное цитирование, что является одним из явлений,
наиболее раздражающих пользователей 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
Может быть, лично вам по каким-либо причинам более удобен формат, использованный вами
в своем ответе; также вполне возможно, что вы можете не соглашаться с соображениями,
изложенными выше. Тем не менее, обращаю ваше внимание, что предлагаемый формат сообщений
является именно тем, что предпочитает большинство активных пользователей RSDN.ru, и,
соответственно, тем, чего они ожидают для комфортного чтения. Следуя принятым здесь
обычаям, вы скорее встретите доброжелательно настроенных собеседников, готовых помочь
и пойти навстречу.
Спасибо.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Дмитрий Федоров, Вы писали:
ДФ>Особенностью 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(); // вызывает все, что было спланировано
Чтобы не возиться с подсчетом ссылок вручную, указатели на синглетон должны быть умными. Например, так:
Конструкторы (без параметров и копирования) и деструктор синглетона имеет смысл закрывать.
Чтобы single_holder мог работать, нужно объявить его другом.
Конструктор копирования вообще не существует — его объявляют, но не определяют.
class my_single
{
friend class single_holder<my_single>;
my_single(const my_single&);
protected: // если допускаем существование наследников
my_single() { . . . }
~my_single() { . . . }
public:
. . .
};
Здравствуйте, Кодт, Вы писали:
К>По ряду причин синглетоны, живущие в DLL, нужно убивать из DllMain(DLL_PROCESS_DETACH), а не из DLL'ского CRT. К>Александреску регистрирует функции-убийцы синглетона в atexit(), я предпочитаю определять у синглетона открытый метод-убийцу или делать аналог atexit() с ручным вызовом всей коллекции в DllMain.
Можно об этом подробнее?
К>Конструкторы (без параметров и копирования) и деструктор синглетона имеет смысл закрывать. К>Чтобы single_holder мог работать, нужно объявить его другом. К>Конструктор копирования вообще не существует — его объявляют, но не определяют. К>
Здравствуйте!
У меня такой вот вопрос:
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...
N>Я знаком с этим типом 'реализации' синглетона, однако не считаю его полноценным синглетоном с точки зрения постановки задачи в начале статьи — возможность управлять временем создания и удаления объекта. В реализации предлагаемой Meyers'ом объект все равно создается и удаляется статически, то есть те проблемы которые описаны в начале статьи статьи остаются в силе.
Ответ неверный. N>Единственную задачу которую решает данная реализация — это гарантия того, что объект существует в единственном экземпляре, а этого не достаточно.
Аналогично.
n>> Единственную задачу которую решает данная реализация — это гарантия того, n>> что объект существует в единственном экземпляре,
ПК>Даже эту задачу данная реализация успешно решает только при условии отсутствия ПК>многопоточности. В это решение корректно синхронизацию добавить весьма проблематично.
Согласен, что синхронизация тут довольно проблематична, впрочем, как и в любом синглтоне. Но решить ее можно, и в соотв. топике форума С++ варинты решений приводились.
Здравствуйте, Кодт, Вы писали:
К>Свисток — это либо выход из программы (код завершения в 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? А для забывчивых есть какое нибудь средство?
Здравствуйте, Anton V. Kolotaev, Вы писали:
AVK>Объект создается при первом обращении и разрушается по выходу и программы. AVK>Гарантируется, что чем позже объект создан, тем раньше он будет разрушен. AVK>Из этого следует, что проблемы возникнут, если в деструкторе одиночка класса A обращается к одиночке класса В, а тот уже разрушен. Это возможно в случае, если одиночка класса В создан позже одиночки класса А... На самом деле интересно, что будет если при закрытии программы после того, как разрушен одиночка B, вызывается деструктор одиночки А, который обращается к одиночке класса В. Будет ли создан заново экземпляр класса В или произойдет сбой?
Однозначно сбой — такие переменные по определению создаются один раз и повторно созданы не будут.
Статья понравилась. Только есть одно замечание — есть там следующий код:
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 rebalancingwhile (__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 rebalancingwhile (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";
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
Raurat_Ltd wrote:
> Во блин, это оказвается стиль такой. Я то думал, что разработчики STL в Майкрософте специально так код изгадили, чтобы его читать было нельзя.
Его изгадили не просто так, а со смыслом. Имена начинающиеся с 2х знаков подчеркивания (__x) или со знака подчеркивания и заглавной буквы (_Key) зарезервированы для использования реализацией стандартной библиотеки во всех контекстах.
Если бы они не использовали зарезервированные имена, то существовала бы вероятность, что некоторое имя из реализации стандартной библиотекии совпадет например с именем пользовательского макроса, и привет.
ДФ>Авторы: ДФ> Дмитрий Федоров
ДФ>Аннотация: ДФ>Особенностью Singleton является то, что он гарантирует существование объекта в единственном экземпляре, а самое главное, то, что он создается в тот момент, когда это требуется клиенту. Последующие попытки конструирования объекта приводят лишь к возвращению клиенту ссылки на уже существующий объект, но не к созданию нового.
Описанная задача исчерпывающе решена очень давно в библиотеке Loki от Андрея Александреску.
При внимательном изучении обоих решений очевидно, что уважаемым автором статьи проделана бесполезная работа
Здравствуйте, Anton V. Kolotaev, Вы писали:
AVK>Объект создается при первом обращении и разрушается по выходу и программы. AVK>Гарантируется, что чем позже объект создан, тем раньше он будет разрушен.
да ну? и кем же это гарантируется интересно.
Re[2]: Meyers singleton: время создания и удаления
От:
Аноним
Дата:
13.10.08 15:15
Оценка:
Здравствуйте, superman, Вы писали:
S>Здравствуйте, Anton V. Kolotaev, Вы писали:
AVK>>Объект создается при первом обращении и разрушается по выходу и программы. AVK>>Гарантируется, что чем позже объект создан, тем раньше он будет разрушен.
S>да ну? и кем же это гарантируется интересно.
Стандартом C++.
Re[3]: Meyers singleton: время создания и удаления
Здравствуйте, CreatorCray, Вы писали:
A>>современная мода — писать подчеркивание в конце переменных: refcount_. CC>Кошмарная мода ИМХО
Согласен. Все знают, что надо писать m_refcount
Re[4]: Маленькое замечание
От:
Аноним
Дата:
20.10.08 08:00
Оценка:
Здравствуйте, oziro, Вы писали:
O>Здравствуйте, CreatorCray, Вы писали:
A>>>современная мода — писать подчеркивание в конце переменных: refcount_. CC>>Кошмарная мода ИМХО
O>Согласен. Все знают, что надо писать m_refcount
Это не мода, это кодинг-стайл — такое же policy проекта, как соглашение о порядке объявления заголовочныхз файлов, порядок юзания сторонних либ etc. И личным предпочтениям — тут не место.
Одно из проявлений профессионализма — уметь писать два проекта одновременно, с разными кодинг-стайлами
Здравствуйте, oziro, Вы писали:
A>>>современная мода — писать подчеркивание в конце переменных: refcount_. CC>>Кошмарная мода ИМХО O>Согласен. Все знают, что надо писать m_refcount
Наименьшее из зол ИМХО.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока