Здравствуйте, MescalitoPeyot, Вы писали:
MP>Здравствуйте, pegarus, Вы писали:
P>>Подскажите, как называется приведённая ниже реализация синглтона? Какие есть недостатки в отличие от синглтона Маерса?
MP>Она называется велосипед с проблемами. Например, не потокобезопасный счетчик первое что бросается в глаза
+1
Однако, преимущества этого подхода перед СМ есть.
operator-> делает более сложным сохранение ссылки/указателя на синглтон.
Т.е. в случае X::Instance().Method() можно написать X& x = X::Instance(); в случае X::instance->Method() это уже сложнее.
Ссылки вида CSingle считаются, так, в отличии от СМ, ситнглтон не будет использован после удаления, а после удеаления последней ссылки если он снова нужен он снова создаётся (разумеется, не-потокобезоасность всё ломает).
Далее, в отличии от СМ этот, похоже, готов к бросающему конструктору.
---
Я пришел к выводу, что лучше синглтон с таким интерфейсом в хедере:
namespace my_singleton
{
T1 method1(P1);
T2 method2(P2);
...
}
Т.е. никаких приватных методов и дата мемберов (как преимущества pImpl), плюс нельзя вообще никак взять его адрес или попытаться скопировать.
И меньше возможностей нарушить ABI незаметно для компоновщика в случае, например, TCHAR дата memberов:
class X : public Singleton<X>
{
...
TCHAR path[MAX_PATH];
} // имплементация c _UNICODE, инстанциируем без _UNICODE - happy debugging :)
Имплементация в .cpp в зависимости от потребностей. Неплохо её запихнуть в глобальную переменную в неймспейс детейл:
namespace my_singleton{namespace detail{
struct data {
...
} = {};
}}
тогда в отладчике в Watch работает в любом месте:
my_singleton::detail::data
(в том числе и в минидампе с MiniDumpWithDataSegs)
Т.к. статической инициализации редко достаточно, нужно как-то обеспечить динамическую инициализацию/финализацию. Тут в зависимости от потребностей, разное можно сделать:
boost::call_once, что-то вроде Синглтона Мейерса, но форсированое конструктором глобального объекта, более интересные трюки. Для финализации может быть полезен прямой вызов atexit.
Т.е. имплементация каждый раз по месту, зависит от конкретного случая, и может быть изменена действительно незаметно для клиента — без перекомпиляции его кода. И никакой шаблонной магии.
Где я бы такое применял. Можно условно разделить синглтоны на:
1. "Глобальные переменные" — менеджеры памяти, врапперы к системным сервисам, жучки для отладки — то что действительно по-любому синглтон. Тут вышеописанный интерфейс синглтона рулит.
2. "Ошибки проектирования" — Классы, содержащие логику приложения, которые всвязи с текущим дизайном сделаны синглтонами, но дизайн может поменятся. Тут лучше сделать синглтонность CRTP-базой.