Понадобился мне тут сабж... в boost'е ничего подобного, к моему глубочайшему удивлению, не обнаружилось; гуглевание по словам "C++ singleton thread safe" выдало лишь массу ссылок на "общие слова", по прочтении которых наваялось вот такое:
class MyOneAndOnly: public Singleton<MyOneAndOnly> { ... };
MyOneAndOnly::GetObject().some_method();
Теперь собственно проблемы/вопросы:
Обращение к методам MyOneAndOnly потенциально возможно из конструкторов/деструкторов глобальных объектов (почему pObject и создается в куче). С первыи проблем, как я понимаю не возникнет, так как при первом же общении произойдет вызов new _Class_t. А вот деструкторами все хуже, потому как никаких гарантий, что уже не был разрушен Locker, у меня нет. Это можно как-то преодолеть?
Очевидно, что когда-то нужно вызвать delete pObject — но как это сделать "безопасно" (то есть, с гарантией, что все глобальные объекты уже разрушены)? Копать в сторону atexit()?
[]
SDB>MyOneAndOnly::GetObject().some_method(); SDB>[/ccode] SDB>Теперь собственно проблемы/вопросы:
SDB> SDB>Обращение к методам MyOneAndOnly потенциально возможно из конструкторов/деструкторов глобальных объектов (почему pObject и создается в куче). С первыи проблем, как я понимаю не возникнет, так как при первом же общении произойдет вызов new _Class_t. А вот деструкторами все хуже, потому как никаких гарантий, что уже не был разрушен Locker, у меня нет. Это можно как-то преодолеть?
SDB>Очевидно, что когда-то нужно вызвать delete pObject — но как это сделать "безопасно" (то есть, с гарантией, что все глобальные объекты уже разрушены)? Копать в сторону atexit()?
SDB>Я правильно понимаю, что реализовать singleton для класса, который не имеет конструктора по умолчанию, невозможно? SDB>
SDB>P.S. SDB>В ожидании ответов пошел читать Паттерн Singleton (Одиночка). Примеры использования
1) Зачем писать свой Locker, когда есть ATL::CComAutoCriticalSection, ATL::CComCritSecLock? Или нет возможности их юзать?
2) Зачем у Locker'а private конструктор? Класс же и так private? Из-за этого тебе пришлось тянуть friend. Сделай конструктор/десруктор public
3) Есть идея создавать CS в куче и вообще не удалять ни твой объект, ни CS. При грохе процесса все почистится. Но это зависит от "сложности" деструктора MyOneAndOnly
4) Может все-таки Loki + напильник?
Здравствуйте, Константин Л., Вы писали:
КЛ>Почему Loki не воспринимаешь?
Сложно сказать... для меня это больше "академический эксперимент" по проверке и демонстрации возможностей C++ и каких-то концепций, чем "боевой" продукт.
КЛ>1) Зачем писать свой Locker, когда есть ATL::CComAutoCriticalSection, ATL::CComCritSecLock? Или нет возможности их юзать?
Нет, нужна максимальная независимость от любых библиотек (исключая STL).
КЛ>2) Зачем у Locker'а private конструктор? Класс же и так private? Из-за этого тебе пришлось тянуть friend. Сделай конструктор/десруктор public
Согласен.
КЛ>3) Есть идея создавать CS в куче и вообще не удалять ни твой объект, ни CS. При грохе процесса все почистится.
За такой подход у нас на работе рихтуют напильником... сначала руки, потом — голову. И очень правильно ИМХО делают.
КЛ>Но это зависит от "сложности" деструктора MyOneAndOnly
Вот именно.
КЛ>4) Может все-таки Loki + напильник?
Нет уж, увольте. Я тут нагугли-таки пару полезных ссылочек по теме со вполне читабельным кодом:
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Здравствуйте, Константин Л., Вы писали:
КЛ>>Почему Loki не воспринимаешь?
SDB>Сложно сказать... для меня это больше "академический эксперимент" по проверке и демонстрации возможностей C++ и каких-то концепций, чем "боевой" продукт.
КЛ>>1) Зачем писать свой Locker, когда есть ATL::CComAutoCriticalSection, ATL::CComCritSecLock? Или нет возможности их юзать?
SDB>Нет, нужна максимальная независимость от любых библиотек (исключая STL).
КЛ>>2) Зачем у Locker'а private конструктор? Класс же и так private? Из-за этого тебе пришлось тянуть friend. Сделай конструктор/десруктор public
SDB>Согласен.
КЛ>>3) Есть идея создавать CS в куче и вообще не удалять ни твой объект, ни CS. При грохе процесса все почистится.
SDB>За такой подход у нас на работе рихтуют напильником... сначала руки, потом — голову. И очень правильно ИМХО делают.
ИМХО тоже, просто предложил как один из "возможных" вариантов
КЛ>>Но это зависит от "сложности" деструктора MyOneAndOnly
SDB>Вот именно.
КЛ>>4) Может все-таки Loki + напильник?
SDB>Нет уж, увольте. Я тут нагугли-таки пару полезных ссылочек по теме со вполне читабельным кодом:
SDB>Singleton.h
Есть сомнения по поводу необходимости наследования от SingletonBase. Этот класс является аналогом boost::noncopyable и ничего не дает кроме невозможности копирования.
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Понадобился мне тут сабж... в boost'е ничего подобного, к моему глубочайшему удивлению, не обнаружилось;
в boost'е есть синглтон — но в виде детали реализации библиотеки pool — boost\pool\detail\singleton.hpp
идея потокобезопасности проста и эффективна — используется синглтон Майерса + instance() первый раз вызывается в конструкторе глобальной переменной, это происходит до входа в main и, следовательно, потокобезопасно.
код примерно такой
template<class T> class singleton : public T
{
private:
...
struct creator
{
creator()
{
singleton<T>::instance();
}
}
static creator s_singleton_creator;
public:
static T& instance()
{
static T inst;
return inst;
}
};
template<class T> typename singleton<T>::creator singleton<T>::s_singleton_creator;
Здравствуйте, Константин Л., Вы писали:
КЛ>ИМХО тоже, просто предложил как один из "возможных" вариантов
Для меня он не возможен, даже в кавычках.
КЛ>Есть сомнения по поводу необходимости наследования от SingletonBase. Этот класс является аналогом boost::noncopyable и ничего не дает кроме невозможности копирования.
Угу.
КЛ>Так что необходимость наследования от него считаю лишней
Ну, это уже частности... при наличии рашпиля.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
Здравствуйте, Ivan, Вы писали:
I>в boost'е есть синглтон — но в виде детали реализации библиотеки pool — boost\pool\detail\singleton.hpp I>идея потокобезопасности проста и эффективна — используется синглтон Майерса + instance() первый раз вызывается в конструкторе глобальной переменной, это происходит до входа в main и, следовательно, потокобезопасно.
Засмотрел. Все бы хорошо, но:
1.
// The following helper classes are placeholders for a generic "singleton"
// class. The classes below support usage of singletons, including use in
// program startup/shutdown code, AS LONG AS there is only one thread
// running before main() begins, and only one thread running after main()
// exits.
Будучи параноиком, выделенным смущен.
2.
// Furthermore, since the instance() function contains the object, instead
// of the singleton_default class containing a static instance of the
// object, that object is guaranteed to be constructed (at the latest) in
// the first call to instance(). This permits calls to instance() from
// static code, even if that code is called before the file-scope objects
// in this file have been initialized.
Увы, но разрушение такого синглетона после всех глобальных объектов, которые им пользовались, не гарантируется.
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Доброго времени суток всем нам!
SDB>Понадобился мне тут сабж... в boost'е ничего подобного, к моему глубочайшему удивлению, не обнаружилось; гуглевание по словам "C++ singleton thread safe" выдало лишь массу ссылок на "общие слова", по прочтении которых наваялось вот такое:
Так на RSDN же и была интересная тема thread safe singlton — возможно ли такое в принципе
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Доброго времени суток всем нам!
SDB>Понадобился мне тут сабж... в boost'е ничего подобного, к моему глубочайшему удивлению, не обнаружилось; гуглевание по словам "C++ singleton thread safe" выдало лишь массу ссылок на "общие слова", по прочтении которых наваялось вот такое:
Ну, вот так всегда: спросишь что-нибудь на RSDN — пошлют в Гугль, а если первым делом скажешь, что в Гугле уже был — "а чего ты на RSDN не посмотрел?.."
Спасибо, Вит, занес ссылку в избранное, почитаю на досуге.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Здравствуйте, DigitalGuru, Вы писали:
DG>>Конечно! У Александреску именно так и написано
SDB>"Great minds think alike..." Но код из Context Singletons — context-specific shared objects in C++ читается значительно приятнее.
Full disclosure: phoenix is based partly on MC++D's code. In particular, i've stolen Andrei's trick of matching atexit(), manual dtor invokation and the placement new operator .
Еще позабавило имя переменной "myers" .
А что касается реализации Singlton'а, то, мне лично, приятнее вот это:
class my_singleton_t {
...
};
extern my_singleton_t my_singleton;
Re[3]: Потоко-бесопасный синглетон
От:
Аноним
Дата:
24.05.06 10:36
Оценка:
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Здравствуйте, Ivan, Вы писали:
[snip]
SDB>1. SDB>
SDB>// The following helper classes are placeholders for a generic "singleton"
SDB>// class. The classes below support usage of singletons, including use in
SDB>// program startup/shutdown code, AS LONG AS there is only one thread
SDB>// running before main() begins, and only one thread running after main()
SDB>// exits.
SDB>Будучи параноиком, выделенным смущен.
А у вас часто создаются нити до входа в main? Правда, очень интересно где это может понадобиться.
[snip]
SDB>Увы, но разрушение такого синглетона после всех глобальных объектов, которые им пользовались, не гарантируется.
Здравствуйте, <Аноним>, Вы писали:
SDB>>Будучи параноиком, выделенным смущен. А>А у вас часто создаются нити до входа в main? Правда, очень интересно где это может понадобиться.
См. выделенное. Мне крайне не хочется копаться в исходниках CRT очередного компилятора, чтобы убедиться, что до входа в main() мы имеем ровно один поток.
А>здесь
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Засмотрел. Все бы хорошо, но:
SDB>1. SDB>
SDB>// AS LONG AS there is only one thread
SDB>// running before main() begins, and only one thread running after main()
SDB>// exits.
если речь идет о Dll модуле, то вызов DllMain происходит внутри спецальной секции LoaderLock и создание других потоков в этот момент будет приостановлено до завершения работы DllMain. В exe модуле технически завести несколько потоков можно — в конструктторах глобальных переменных, но я с таким не встречался.
если представить, что кто-то создает потоки в конструкторах глобальных переменных, то в это время еще не завершилась инициализация CRT в главном потоке — это может создать проблемы при инициализации CRT в порожденных потоках. и второй момент — при обращении из этих потоков к глобальным переменным — можно получить доступ к переменным, которые еще не успели сконструироваться в главном потоке.
SDB>Увы, но разрушение такого синглетона после всех глобальных объектов, которые им пользовались, не гарантируется.
да, здесь похоже по стандарту UB при обращении после его разрушения, на практике для Visual C++ — он 'возродится'
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Ну, вот так всегда: спросишь что-нибудь на RSDN — пошлют в Гугль, а если первым делом скажешь, что в Гугле уже был — "а чего ты на RSDN не посмотрел?.."
Хочешь я тебе тулзу дам, которая ищет одновременно и там, и там, объединяя результаты вместе? Только я её пока в гугль-группах и на codeproject искать не научил, но это в планах есть...
SDB>Спасибо, Вит, занес ссылку в избранное, почитаю на досуге.
Смущает пара моментов, вроде в ветке не упоминались: SDB>
SDB> static Locker m_objectLocker; // 1) инициализируется в runtime - обращение
// к GetObject из других единиц трансляции
// может обломиться
SDB>template <class _Class_t>
SDB>_Class_t& Singleton<_Class_t>::GetObject(void)
SDB>{
SDB> m_objectLocker.Enter();
SDB> static _Class_t* pObject;
SDB> if (pObject == NULL)
SDB> {
SDB> pObject = new _Class_t();// 2) маловероятно, но может бросить исключение,
SDB> }
SDB> m_objectLocker.Leave(); // ...и сюда мы не попадаем
SDB> return (*pObject);
SDB>}
SDB>
SDB>Теперь собственно проблемы/вопросы:
SDB>[list=1] SDB>Обращение к методам MyOneAndOnly потенциально возможно из конструкторов/деструкторов глобальных объектов (почему pObject и создается в куче). С первыи проблем, как я понимаю не возникнет,
См. 1), могут возникнуть.
Здравствуйте, Ivan, Вы писали:
I>да, здесь похоже по стандарту UB при обращении после его разрушения, на практике для Visual C++ — он 'возродится'
насчет 'возродится' я погорячился , после вызова деструктора новый экземпляр не будет создан и в visual c++ (проверил на 2005)
Здравствуйте, Programmierer AG, Вы писали:
PA>Смущает пара моментов, вроде в ветке не упоминались: SDB>>
SDB>> static Locker m_objectLocker; // 1) инициализируется в runtime - обращение
PA> // к GetObject из других единиц трансляции
PA> // может обломиться
SDB>> pObject = new _Class_t();// 2) маловероятно, но может бросить исключение,
SDB>> m_objectLocker.Leave(); // ...и сюда мы не попадаем
SDB>>
Здравствуйте, Conr, Вы писали:
C>Хочешь я тебе тулзу дам, которая ищет одновременно и там, и там, объединяя результаты вместе? Только я её пока в гугль-группах и на codeproject искать не научил, но это в планах есть...
Ну, вот как допишешь...
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>М-дя... 2)-е легко объехать как-то а-ля
Или по старинке, через RTTI. SDB>А вот с 1)-м и правда засада... хотя можно, конечно, "высокоприоритетной" #pragma init_seg() воспользоваться.
Или сделать инициализацию на Schwarz counter'ах. Хотя если допустить, что конструкторы глобальных объектов могут создавать потоки, безопасная и прозрачная инициализация синглтона+его мьютекса у меня в голове не укладывается.
Здравствуйте, Ivan, Вы писали:
I>Здравствуйте, Ivan, Вы писали:
еще один не вполне "законный" и непереносимый вариант обойти проблему порядка создания/разрушения — использовать CRTALLOC/init_seg — чтобы синглтон гарантированно создавался до первого конструктора глобального объекта и следовательно разрушался после вызова деструктора последнего такого объекта
template<class T> class singleton : public T
{
private:
static int creator()
{
singleton<T>::instance();
return 0;
}
static int (__cdecl *pcreator)();
public:
static T& instance()
{
static int use_pcreate = pcreator(); //static singleton<T> inst;
return inst;
}
};
#pragma data_seg(".CRT$XIC")
template<class T> __declspec(allocate(".CRT$XIC")) int (__cdecl *singleton<T>::pcreator)() = singleton<T>::creator;
#pragma data_seg()
Здравствуйте, Ivan, Вы писали:
I>еще один не вполне "законный" и непереносимый вариант обойти проблему порядка создания/разрушения — использовать CRTALLOC/init_seg — чтобы синглтон гарантированно создавался до первого конструктора глобального объекта и следовательно разрушался после вызова деструктора последнего такого объекта
О, вот за эту идею спасибо! Непереносимость меня не заботит совершенно, а вот законность-то тут чем нарушается?
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>О, вот за эту идею спасибо! Непереносимость меня не заботит совершенно, а вот законность-то тут чем нарушается?
под незаконностью я имел в виду недокументированность идентификаторов CRT, с помощью которых можно управлять порядком. $XI — это C инициализаторы, $XC — c++,
но в будущих версиях CRT это могут изменить
и потенциальная проблема здесь — два таких синглтона будут создаваться/разрушаться уже в проивзольном порядке относительно друг друга — хотя этим уже можно управлять (в том числе и подкручивая идентификатор секции)
Здравствуйте, Ivan, Вы писали:
I>но в будущих версиях CRT это могут изменить
Что-то я сомневаюсь. Такие вещи МС обычно блюдет, насколько я знаю.
I>и потенциальная проблема здесь — два таких синглтона будут создаваться/разрушаться уже в проивзольном порядке относительно друг друга
Да, это первое, что пришло мне в голову.
I> — хотя этим уже можно управлять (в том числе и подкручивая идентификатор секции)
Угу. В любом случае — вариант очень интересный, а главное железный. Я вот сейчас еще ZThread смотрю, что там Eric Crahen накрутил.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
Для остальных интерфейсов делаются аналогичные специализации InterfaceIID.
При реализации GetServiceByIID можно использовать любые стратегии создания/разрушения сервисов.
Все остальное один в один как в примере на C#.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
и дальше. WH>Для остальных интерфейсов делаются аналогичные специализации InterfaceIID. WH>При реализации GetServiceByIID можно использовать любые стратегии создания/разрушения сервисов. WH>Все остальное один в один как в примере на C#.
имхо, этот подход не заменяет синглтон по двум причинам:
— доступ к "главному" провайдеру IServicepProvider, этот Service Provider напрашивается быть реализованным с помощью шаблона синглтон
— сложность. для простых приложений это может стать overkill'ом. допустим для небольшого консольного приложения нужна конфигурация и простая подсистема логирования. для них можно применить синглтон.
можно зайти и с другой стороны.
допустим для приложения реализована подсистема логирования в виде синглтона. с течением времени требования к системе логирования увеличиваются, появляется необходимость в управлении логированием в зависимости от контекста и т.п. в этом случае синглтон Logger становится уже IServiceProvider'ом и перенаправляет клиентов в зависимости от контекста в нужную реализацию. при правильной начальной реализации для клиентов этот переход может быть прозрачным.
>Почитал я тут... во истину кривая архитектура порождает кривые решения.
поэтому на мой взгляд, синглтон и сервисы/конексты дополняют друг друга и использования одного и/или другого никак не свидетельсвует о хорошей или плохой архитектуре.
Здравствуйте, Ivan, Вы писали:
I>имхо, этот подход не заменяет синглтон по двум причинам: I>- доступ к "главному" провайдеру IServicepProvider, этот Service Provider напрашивается быть реализованным с помощью шаблона синглтон
Я ни разу его синглетоном не делал. Конечно он всегда один но глабольной точки доступа к нему нет. I>- сложность. для простых приложений это может стать overkill'ом. допустим для небольшого консольного приложения нужна конфигурация и простая подсистема логирования. для них можно применить синглтон.
Моя практика показывает что такое прокатывает только оочень простых программках.
А конфиг + логгер (если вспомнить начало топика то и многопоточность) это уже не очень простое приложение.
I>можно зайти и с другой стороны. I>допустим для приложения реализована подсистема логирования в виде синглтона. с течением времени требования к системе логирования увеличиваются, появляется необходимость в управлении логированием в зависимости от контекста и т.п. в этом случае синглтон Logger становится уже IServiceProvider'ом и перенаправляет клиентов в зависимости от контекста в нужную реализацию. при правильной начальной реализации для клиентов этот переход может быть прозрачным.
Продемонстрируй.
>>Почитал я тут... во истину кривая архитектура порождает кривые решения. I>поэтому на мой взгляд, синглтон и сервисы/конексты дополняют друг друга и использования одного и/или другого никак не свидетельсвует о хорошей или плохой архитектуре.
Всетки в случае с большими приложениями дерево контекстов само формирует каркас ситемы разделяя ее на четкие слои, а без четкой структуры приложения что-то большее чем "Hello world!" написать проблематично.
Синглитоны таким свойством не обладают.
К тому же контексты гораздо слабее связывают систему что есть благо.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
I>>можно зайти и с другой стороны. I>>допустим для приложения реализована подсистема логирования в виде синглтона. с течением времени требования к системе логирования увеличиваются, появляется необходимость в управлении логированием в зависимости от контекста и т.п. в этом случае синглтон Logger становится уже IServiceProvider'ом и перенаправляет клиентов в зависимости от контекста в нужную реализацию. при правильной начальной реализации для клиентов этот переход может быть прозрачным. WH>Продемонстрируй.
Продемонстрирую на примере COM. созданием экзмепляров управляет фабрика классов — будет компонент синглтоном или нет — зависит от ее реализации и никак не влияет ни на клиентов, ни на реализацию самого компонента. Контекстами и дополнительными сервисами в зависимости от контекста занимается отдельная подсистема, построенная на основе концепции Proxy. клиент получает вместо указателя на компонент — Proxy, которая в зависимости от контекста и его свойств добавляет нужную функциональность. снова это не влияет ни на реализацию клиента, ни на реализацию компонента и никак не связано с фабрикой классов этого компонента.
хороший пример синглтона/провайдера сервисов — GIT (Global Interface Table), у клиентов есть глобальная точка доступа к GIT, т.к. она стнглтон, в самой GIT могут храниться указатели на различные компоненты — это уже провайдер определенных сервисов.
повторяя этот дизайн и идеи — т.е. используя шаблоны проектирования "фабрика" и "прокси", можно реализовать Logger так, что новая функциональность будет добавляться прозрачно для клиентов. при этом является ли Logger синглтоном или учитывает ли контекст клиента станет деталью реализации подсистемы логирования.
Здравствуйте, Ivan, Вы писали:
I>повторяя этот дизайн и идеи — т.е. используя шаблоны проектирования "фабрика" и "прокси", можно реализовать Logger так, что новая функциональность будет добавляться прозрачно для клиентов. при этом является ли Logger синглтоном или учитывает ли контекст клиента станет деталью реализации подсистемы логирования.
С СОМом я работал очень давно и глубоко не лазил.
Пожалуйста накидай несколько строк псевдокода чтобы понятно было кто на ком стоит.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Я правильно понимаю, что реализовать singleton для класса, который не имеет конструктора по умолчанию, невозможно?
Можно воспльзоваться библиотекой lib-global.
Она реализует те же задачи, что и паттерн Singleton, но плюс к этому позволяет работать
с классами, у которых нет конструктора по умолчанию.
SDB>Рассматривая исходники ZThread, обнаружил следующее:
SDB>
SDB>template <class T, class InstantiationPolicy, class LockType>
SDB>T* Singleton<T, InstantiationPolicy, LockType>::instance() {
SDB> // Uses local static storage to avoid static construction
SDB> // sequence issues. (regaring when the lock is created)
SDB> static T* ptr = 0;
SDB> static LockType lock;
SDB> if(!ptr) {
SDB> Guard<LockType, LockedScope> g(lock);
SDB> if(!ptr)
SDB> InstantiationPolicy::create(ptr);
SDB> }
SDB> return const_cast<T*>(ptr);
SDB> }
SDB>};
SDB> SDB>Поджирненный комментарий поверг меня в некоторое недоумение... откуда у автора такая уверенность?
Я полагаю, имеется в виду, что согласно стандарту, инициализация локальных статических объектов (не POD) производится до выполнения первой инструкции функции. Насколько я помню, про POD там оговорено отдельно.
Т.о., несмотря на уверенный комментарий, static LockType lock возвращает нас все к той же проблеме — нельзя использовать в качестве локера не POD типы. Видимо, автор не в курсе проблематики.
SDB>Обращение к методам MyOneAndOnly потенциально возможно из конструкторов/деструкторов глобальных объектов (почему pObject и создается в куче). С первыи проблем, как я понимаю не возникнет, так как при первом же общении произойдет вызов new _Class_t. А вот деструкторами все хуже, потому как никаких гарантий, что уже не был разрушен Locker, у меня нет. Это можно как-то преодолеть?
Для синглтона Мейерса это не является проблемой. А вот с выделенным мной фрагментом кода возникает _очень_ много проблем, связанных с неопределенным порядком инициализации. По сути, нам нужен МТ синглтон в МТ синглтоне — локер ведь тоже обязан быть синглтоном. Решение уже приводили — http://www.rsdn.ru/Forum?mid=531518
Т.е., фактически, все упирается в использовании POD типов в качестве объектов блокировки — так называемый LW мьютекс.
SDB>Очевидно, что когда-то нужно вызвать delete pObject — но как это сделать "безопасно" (то есть, с гарантией, что все глобальные объекты уже разрушены)? Копать в сторону atexit()?
Да. И читать Александреску
SDB>Я правильно понимаю, что реализовать singleton для класса, который не имеет конструктора по умолчанию, невозможно?
Возможно, например, использованием трейтов на создание экземпляра.
struct MyCreator
{
type *Create()
{
return new Type(params)
// или (тут надо осторожнее, чтобы компилятор не принял след. строку за объявление функции)static Type t(params);
return &t;
}
Destroy(type *t)
{
// etc
}
}
Вообще, тут надо _обязательно_ использовать трейты. А лучше взять синглтон из локи и покромсать его под свои нужды. Там все было прозрачно.
PS
Синглтон — это очень неоднозначная штука. Если можно обойтись без него — например, просто объявить глобальную переменную — то лучше это сделать. Паттераны и т.п. — это все красиво. В теории. Но жизнь, как обычно, вносит свои коррективы.