Re: Singleton руками
От: agg  
Дата: 26.05.09 05:57
Оценка:
Всем большое спасибо за участие в обсуждении, тестировал в XCODE 3.1.2, Simulator 2.2.1 и вот собственно говоря плод всех дебатов:
//2009 A.Gordienko Implementation of Singleton for iPhone OS. 
#ifndef SINGLETON_H
#define SINGLETON_H

template <class T> struct CreateUsingNew
{
    static T* Create()
    { return new T; }
    
    static void Destroy(T* p)
    { delete p; }
};

template <class T> struct CreateStatic
{
    static T* Create()
    {
        static T instance;
        t = &instance;
        return t;
    }
    
    static void Destroy(T* p)
    {
        assert(p == t);
        t->~T();
    }
private:
    static T* t;
};

template<class T>T* CreateStatic<T>::t=0;

template<class T, template <class> class CreationPolicy = CreateUsingNew> class Singleton 
{
    typedef T ObjectType;
public:
    static T& Instance();
private:
    Singleton(){}
    static void DestroySingleton();
    static T* _instance;
};


template<class T, template <class> class CreationPolicy>
inline T& Singleton<T, CreationPolicy>::Instance()
{
    if (!_instance)
    {
        _instance = CreationPolicy<T>::Create();
        if(_instance)
            atexit(Singleton<T,CreationPolicy>::DestroySingleton);        
    }
    return *_instance;
}

template<class T, template <class> class CreationPolicy>
inline void Singleton<T, CreationPolicy>::DestroySingleton()
{
    if(_instance)
    {
        CreationPolicy<T>::Destroy(_instance);
    }    
}

template <class T,template <typename T> class CreationPolicy>T* Singleton<T,CreationPolicy>::_instance=0;
#endif
Re[3]: Singleton руками
От: Erop Россия  
Дата: 26.05.09 06:42
Оценка:
Здравствуйте, Аноним, Вы писали:

А>встречный вопрос, а почему не подходит более простой вариант?


А ничего, что деструктор будет вызван дважды?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Singleton руками
От: Erop Россия  
Дата: 26.05.09 07:27
Оценка:
Здравствуйте, agg, Вы писали:

agg>Всем большое спасибо за участие в обсуждении, тестировал в XCODE 3.1.2, Simulator 2.2.1 и вот собственно говоря плод всех дебатов:


Мои скромные замечания.
1) Зачем нужно поле CreateStatic::t? Оно же дублирует поле Singleton::_instance?
2) В случае CreateStatic деструктор объекта позовётся дважды.
3) Так как синглетон ленивый, возможны всякие странные эффекты. Суть которых состоит в том, что мы можем создать синглетон слишком поздно (типа уже на этапе разрушения статических объектов), либо, наоборот, слишком рано, из-за чего к нему кто-то обратиться уже после разрушения объекта...

Мои скромные вопросы
1) А что делать, если мне надо два разных синглетона одного типа? Скажем две строки? Или T -- это в принципе свой хитрый, самописный класс, у которого нельзя создавать два экземпляра? Почему тогда "синглетонность" прикручивают к нему снаружи?
2) Зачем вообще выбор между политиками аллокации? Какие будут рекомендации для пользователей, какую когда выбрать?
3) Чем это лучше, чем синглетон Майерса?
4) Если уж так нужны политики, то от чего бы не сделать два разных синглетона и всё?
5) А что делать, если я хочу инициализировать синглетон не конструктором по умолчанию, а как-то ещё?

Мои скромные предложения.
Вариант 1.
Пользоваться статическими переменными и не страдать... На крайняк можно иметь конструкцию вроде:
class CSingletonBase {
public:
    bool IsReady() const { return isReady; }
protected:
    CSingletonBase() : isReady( true ) {}
    ~CSingletonBase() { isReady = false; }
private:
    bool isReady;
};
и выводиться из неё.

Либо, можно сделать что-то вроде:
template<typename T> CStaticData : CSingletonBase {
    T Data;
public:
    CStaticData() {}
    template<typename Arg1>
    CStaticData( const Arg1& initWith1 ) : Data( initWith1 ) {}
    // Можно досыпать шаблонных конструкторов по вкусу

    T& Get() { assert( IsReady() ); return Data; }
    const T& Get() const  { assert( IsReady() ); return Data; }
};


Ну и заводить просто глобальные переменные нужных типов. Скажем extern CStaticData<std::string> logBuffer;
где-то в Cpp можно написать: CStaticData<std::string> logBuffer = "Начало зависи в лог: " + getFormattedTime + "\r\n";
Ну и везде писать потом logBuffer.Get()

Вариант 2
Если таки уж очень нужно сохранить текущую схему, то я бы конечно переписал по крайней мере это:
template <class T> struct CreateStatic
{
    static T* Create()
    {
        static T instance;
        return &instance;
    }
    
    static void Destroy(T* p)
    {
        assert(p == &instance);
    }
};
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Singleton руками
От: agg  
Дата: 26.05.09 09:05
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, agg, Вы писали:


agg>>Всем большое спасибо за участие в обсуждении, тестировал в XCODE 3.1.2, Simulator 2.2.1 и вот собственно говоря плод всех дебатов:


E>Мои скромные замечания.

E>1) Зачем нужно поле CreateStatic::t? Оно же дублирует поле Singleton::_instance?
E>2) В случае CreateStatic деструктор объекта позовётся дважды.
E>3) Так как синглетон ленивый, возможны всякие странные эффекты. Суть которых состоит в том, что мы можем создать синглетон слишком поздно (типа уже на этапе разрушения статических объектов), либо, наоборот, слишком рано, из-за чего к нему кто-то обратиться уже после разрушения объекта...

E>Мои скромные вопросы

E>1) А что делать, если мне надо два разных синглетона одного типа? Скажем две строки? Или T -- это в принципе свой хитрый, самописный класс, у которого нельзя создавать два экземпляра? Почему тогда "синглетонность" прикручивают к нему снаружи?
E>2) Зачем вообще выбор между политиками аллокации? Какие будут рекомендации для пользователей, какую когда выбрать?
E>3) Чем это лучше, чем синглетон Майерса?
E>4) Если уж так нужны политики, то от чего бы не сделать два разных синглетона и всё?
E>5) А что делать, если я хочу инициализировать синглетон не конструктором по умолчанию, а как-то ещё?

Замечания
1) Разумно
2) CreateStatic::Destroy не доглядел, первая реализация метода Create была с использованием размещающего new, поэтому и остался вызов деструктора в методе CreateStatic::Destroy
3) У меня есть мысль как как реализовать стратегию феникс, чтобы если он уничтожен возраждался из пепла , но пока сложно, тем более я это делал чтобы это компилилось и работало для iPhone OS, для обычных операционок в том числе и для MAC OS лучше взять Loki там реально все круто с синглтоном и я всегда пользовался ей, просто для iPhone нет реализации Loki, и принцип я брал именно оттуда.

Вопросы
1)Ну я так понял возник вопрос использования вот пример:

#include "Singleton.h"
class A
{
    friend struct CreateStatic<A>;
    A(){}
    A(const A&a)
    {}
    A& operator=(const A&a){return *this;}
public:
    int f()
    {
        int h=999;
        return h;
    }    
};
typedef Singleton<A,CreateStatic> SinglA;


использовать вот так:
...
SinglA::Instance().f();
...


2) Политика аллокации нужна если к примеру у тебя на устройстве динамически создавать очень медленно, ну и гибкость она не помешает.
3) Я разве сказал что синглтон Майерса хуже, он хуже только тем что к синглтону Маерса не прикрутишь стратегию создания в куче.
4) Как угодно уважаемый делайте, но я приучаю себя делать гибко и правильно.
5) Делайте метод Initialize или что-то вроде этого.

Спасибо за удачные замечания.
Re[3]: Singleton руками
От: agg  
Дата: 26.05.09 11:10
Оценка:
E>Мои скромные предложения.
E>Вариант 1.
E>Пользоваться статическими переменными и не страдать... На крайняк можно иметь конструкцию вроде:
class CSingletonBase {
E>public:
E>    bool IsReady() const { return isReady; }
E>protected:
E>    CSingletonBase() : isReady( true ) {}
E>    ~CSingletonBase() { isReady = false; }
E>private:
E>    bool isReady;
E>};
и выводиться из неё.


E>Либо, можно сделать что-то вроде:
template<typename T> CStaticData : CSingletonBase {
E>    T Data;
E>public:
E>    CStaticData() {}
E>    template<typename Arg1>
E>    CStaticData( const Arg1& initWith1 ) : Data( initWith1 ) {}
E>    // Можно досыпать шаблонных конструкторов по вкусу

E>    T& Get() { assert( IsReady() ); return Data; }
E>    const T& Get() const  { assert( IsReady() ); return Data; }
E>};


E>Ну и заводить просто глобальные переменные нужных типов. Скажем extern CStaticData<std::string> logBuffer;

E>где-то в Cpp можно написать: CStaticData<std::string> logBuffer = "Начало зависи в лог: " + getFormattedTime + "\r\n";
E>Ну и везде писать потом logBuffer.Get()

E>Вариант 2

E>Если таки уж очень нужно сохранить текущую схему, то я бы конечно переписал по крайней мере это:
template <class T> struct CreateStatic
E>{
E>    static T* Create()
E>    {
E>        static T instance;
E>        return &instance;
E>    }
    
E>    static void Destroy(T* p)
E>    {
E>        assert(p == &instance);
E>    }
E>};

E>


Предложение по коду мне откровенно не нравится из-за своей не гибкости и полным отсутствием изящности кода, это не реализация паттерна синглтон, а просто штука способная залепить определенную дырку, но любой код имеет право на существование и это всего лишь мое мнение. Вы написали новую реализацию CreateStatic::Destroy откуда там возьмется instance непонятно, если убрать t то нужно будет убрать проверку адресов p и t что не очень хорошо.
Re: Singleton руками
От: Caracrist https://1pwd.org/
Дата: 26.05.09 12:21
Оценка: 7 (1)
Здравствуйте, agg, Вы писали:

agg>Здравствуйте, встала задача написать Singleton для iPhone, посмотрел иходник из Loki и вот что получилось:


agg>Но никакие финты не помогли, такое предчувствие что я переработал и немного затупил, подскажите пожалуйста как правильно занулить статический указатель?


Во первых нет смысла заморачиваться с CreationPolicy, всегда для синглтона можно сделать дефолтный конструктор.
Во вторых ваша система полетит при мульти трединге.
Предлагаю вариант на случай если мульти трединг и скорость доступа актуальны.
(код под винду)


template <typename T>
class SingletoneS
{
  static T * CreateSingletone()
  {
    if (::InterlockedIncrement(&m_Lock) == 1)
    {
        _instance = new T();
    }
    else 
        WaitForSingleObject(m_lSignal,INFINITE);
    Instance = ReturnInstance;
    SetEvent(m_lSignal);
    return Instance();
  }
  static T * ReturnInstance()
  {
    return _instance;
  }
  static T * _instance;
  static volatile LONG m_Lock;
  static HANDLE m_lSignal;
public:
  static void Reset()
  {
     T * temp = _instance;
     _instance = NULL;
     ResetEvent(m_lSignal);
     Instance = CreateSingletone;
     delete temp;
  }
  static T * (__cdecl * Instance)(void) ; 
};
template <typename T> T * SingletoneS<T>::_instance = NULL;
template <typename T> volatile LONG SingletoneS<T>::m_Lock = 0;
template <typename T> T * (__cdecl * SingletoneS<T>::Instance)(void) = SingletoneS<T>::CreateSingletone;
template <typename T> HANDLE SingletoneS<T>::m_lSignal = CreateEvent(NULL,NULL,false,NULL);

template <typename T> T * Singletone()
{
  return SingletoneS<T>::Instance();
}

#define DefineSingletone(Class) \
private:\
    friend class SingletoneS<Class>; \
    Class();
~~~~~
~lol~~
~~~ Single Password Solution
Re[2]: Singleton руками
От: Caracrist https://1pwd.org/
Дата: 26.05.09 12:36
Оценка:
C>
...
C>public:
C>  static void Reset()
C>  {
C>     T * temp = _instance;
C>     _instance = NULL;
C>     ResetEvent(m_lSignal);
       m_Lock = 0;//пропустил строчку...
C>     Instance = CreateSingletone;
C>     delete temp;
C>  }
...
~~~~~
~lol~~
~~~ Single Password Solution
Re[4]: Singleton руками
От: Erop Россия  
Дата: 26.05.09 13:27
Оценка:
Здравствуйте, agg, Вы писали:


agg>Замечания

agg>3) У меня есть мысль как как реализовать стратегию феникс, чтобы если он уничтожен возраждался из пепла , но пока сложно, тем более я это делал чтобы это компилилось и работало для iPhone OS, для обычных операционок в том числе и для MAC OS лучше взять Loki там реально все круто с синглтоном и я всегда пользовался ей, просто для iPhone нет реализации Loki, и принцип я брал именно оттуда.

Зачем иметь возможность выбора стратегии ДЛЯ КАЖДОГО СИНГЛЕТОНА? Почему бы сразу для всех не выбраь и не закрепить этот выбор в шаблоне класса Singleton?

agg>использовать вот так:

agg>
agg>SinglA::Instance().f();
agg>


Я про другое спрашивал. Что делать если я хочу иметь два синглетона одного типа. Например две таблицы какие-нибудь разные, но однотипные?..

agg>2) Политика аллокации нужна если к примеру у тебя на устройстве динамически создавать очень медленно, ну и гибкость она не помешает.

Ну если на устрйостве надо синглетоны создавать не динамически, а статически, то и что? Почему бы жтот выбор не далеть сразу дял всех синглетонов этого устройства?
agg>3) Я разве сказал что синглтон Майерса хуже, он хуже только тем что к синглтону Маерса не прикрутишь стратегию создания в куче.
Почему? Создайшь по new И регишь в atexit...
Выбор не прикрутишь, это да. Но я не понимаю, зачем нужен выбор...

agg>5) Делайте метод Initialize или что-то вроде этого.

Э-э-э, а откуда его вызывать? И что будут делать коиенты синглетона, обратившиеся к нему до того, как я этот метод позвал?

agg>Спасибо за удачные замечания.

Всегда пожалуйста, но для спасибо тут есть кнопки
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Singleton руками
От: Erop Россия  
Дата: 26.05.09 14:53
Оценка:
Здравствуйте, agg, Вы писали:

agg>Вы написали новую реализацию CreateStatic::Destroy откуда там возьмется instance непонятно, если убрать t то нужно будет убрать проверку адресов p и t что не очень хорошо.

Понял! Ну да, можно у своего же Create спросить адрес, в принципе...

1) Тут принято обращение на "ты".
2) Чем тебе t нравится больше, чем &instance? Ведь они должны быть равны в деструкторе? Зачем хранить этот адрес ещё и в отдельной переменной? Его же можно спросить у себя же?


Что касается гибкости и негибкости, то я
1) Не понимаю зачем нужна гибкость именно в этом месте. Вот гибкость в вариантах инициализации или гибкость в том, что можно иметь несколько синглетонов одного типа -- это я понимаю зачем надо. А зачем надо иметь возможность рулить стратегией аллокации синглетона -- не понимаю. Если на какой-то платформе надо хранить синглетоны так-то, то это значит что на этой платфориме надо использовать модифицированный шаблон синглетона... Может быть, если ты приведёшь юзкейс, демонстрирующий когда нужно использовать не стратегию аллокации синглетонов по умолчанию, а какую-то другую, то станет понятнее зачем нужна гибкость такого рода...
2) Ненужную гибкость считаю вредной. Так как это лишний повод ошибиться...
3) Единственная опция, в нужность которой я готов поверить -- это феникс, хотя тоже сомнительно, конечно. Ну так вот, для феникса, вроде бы, должно быть всё равно, какая там у нас стратегия аллокации...
Пересоздавай да и радуйся...

Можно, кстати, пойти ещё и по третьему пути -- аллокировать место под объект и никогда его не освобождать. Потом в этом месте создавать и разрушать объект синглетона. И сделать его возраждение опциональным...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Singleton руками
От: Erop Россия  
Дата: 26.05.09 20:26
Оценка:
Здравствуйте, Caracrist, Вы писали:

C>Во вторых ваша система полетит при мульти трединге.

А разве на iPhone такое бывает?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Singleton руками
От: Caracrist https://1pwd.org/
Дата: 26.05.09 20:45
Оценка: 14 (1)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Caracrist, Вы писали:


C>>Во вторых ваша система полетит при мульти трединге.

E>А разве на iPhone такое бывает?

Google for "NSThread c++"
~~~~~
~lol~~
~~~ Single Password Solution
Re[4]: offtopic
От: Dair Россия  
Дата: 30.05.09 11:57
Оценка: +1
I>Круто. Даже это уже хорошо. Я просто думал, что при отсутствии желания писать на Object-C остается возможность писать только на голом Си. В аппле сторе с таким си++ вставками тоже принимают?

У нас "нутро" проекта на C++ и с STL. Продаётся на AppStore.
На Objective-C необходимо (хотя и в этом не уверен) писать интерфейсные части.

Кстати, ObjC — отличный язык
Re[5]: offtopic
От: Erop Россия  
Дата: 30.05.09 14:27
Оценка:
Здравствуйте, Dair, Вы писали:

D>Кстати, ObjC — отличный язык

+500!!!
Для GUI и всякого интеропа так вообще супер!!!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: offtopic
От: ilvi Россия  
Дата: 31.05.09 15:35
Оценка:
Здравствуйте, Dair, Вы писали:

D>У нас "нутро" проекта на C++ и с STL. Продаётся на AppStore.

D>На Objective-C необходимо (хотя и в этом не уверен) писать интерфейсные части.

D>Кстати, ObjC — отличный язык


Ясно. Это действительно радует. По поводу языка ObjC я только учусь его готовить и некоторые моменты мне пока не подуше
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.