1. C++ / Говнокод #13908

    +16

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    // in .h file
    class Singleton
    {
    public:
        Singleton();
        ~Singleton();
    private:
        static Singleton* m_Instance;
        friend Singleton& GetInstance();
    };
    
    inline Singleton& GetInstance()
    {
        assert(Singleton::m_Instance);
        return *Singleton::m_Instance;
    }
    
    // in .cpp file
    Singleton* Singleton::m_Instance = NULL;
    
    Singleton::Singleton()
    {
        assert(!m_Instance);
        m_Instance = this;
    }
    
    Singleton::~Singleton()
    {
        m_Instance = NULL;
    }

    Вот такую реализацию синглтона увидел в одном проекте.
    ЗЫ: Для его корректной работы, в main было написано конечно же:
    main() {
    Singleton* s = new Singleton;
    ...
    delete s;
    }

    Запостил: Deacon, 08 Октября 2013

    Комментарии (25) RSS

    • Кстати, в QApplication та же фигня. Вот только QApplication требует argv и argc и, вероятно, они могут повлиять на инициализацию.

      > delete s;

      очередной неосилятор std::unique_ptr / auto_ptr

      Так что говном я бы этот синглтон не назвал. А вот его использование точно говно
      Ответить
      • > Так что говном я бы этот синглтон не назвал.
        Да почему. Реализация - говно ;)

        > очередной неосилятор std::unique_ptr / auto_ptr
        Да вполне можно было как с QApplication - тупо описать переменную где-то вверху main'а. Как раз и финализация вовремя сработает.
        Ответить
        • описание переменных с конструктором до main чревато
          Ответить
          • А кто предлагает до main? В Qt оно описывается в main:)
            int main(int argc, char **argv) {
                QApplication app(argc, argv);
                // ...
                return 0;
            }
            Ответить
      • показать все, что скрыто
        ~Клуб знакомств для геев~
             Познакомлюсь с парнем
             Сделаю миньет, подставлю попку парню кавказской внешности.
             Прут наглые хуястые самцы, желательно с большим членом, так как  
             очко сильно раздолблено. Могу принять сразу до 3-х парней.
                Пишите [email protected]  /Тарас/
        Ответить
    • Синглтоны с инициализацией в main'е, кстати, имеют смысл. Ленивая инициализация без параметров ведь не всегда прокатывает... Правда можно сделать это покрасивей и поудобней.

      А глобальный GetInstance(), не являющийся методом класса, это эпично ;)
      Ответить
      • Я, кстати, часто так делаю. Инициализирую все долгоживущие ресурсы на стеке в main до начала многопоточного кода, и передаю ссылки на них всем потребителям.
        Ответить
        • Этакий DI-на-коленке ;) Кстати, а под кресты есть DI фремворки?
          Ответить
          • Видел вот этот https://code.google.com/p/autumnframework/
            Никогда не пробовал
            Ответить
      • показать все, что скрыто
        ~Клуб знакомств для геев~
             Познакомлюсь с парнем
             Сделаю миньет, подставлю попку парню кавказской внешности.
             Прут наглые хуястые самцы, желательно с большим членом, так как  
             очко сильно раздолблено. Могу принять сразу до 3-х парней.
                Пишите [email protected]  /Тарас/
        Ответить
    • Могло бы иметь право на жизнь, если бы деструктор был виртуальным.
      А вообще, это не Singleton, а коряво реализованный Monostate.
      Ответить
    • Это IMO (простите за каламбур) "правильный" синглтон.

      Я где есть возможность все синглтоны в подобное конверчу (если нет возможности их убрать вообще). Решает самые главные проблемы: известный порядок инициализации синглтонов, обработка ошибок инициализации синглтона и передача параметров в инициализацию синглтона (которые иногда зависят от других синглтонов).

      Так что меня сильно не удивит (не смотря на низкую вероятность) если ты в мой код смотришся. :D
      Ответить
      • А я вот так делал, когда мне важен был порядок и аргументы, по аналогии с QApplication:
        int main() {
            some_singleton foo(42);
            other_singleton bar("djigurda", &foo);
            // ...
            return 0;
        }
        // ...
        void foo::bar() {
            other_singleton & bar = other_singleton::get_instance();
            bar.djigurda();
        }
        Ответить
        • я предпочитаю динамически алоцировать, потому что были случаи когда синглтоны нужно было переинициализировать (типичный пример глобальная конфигурация). мне проще делать lock/delete/new/unlock, чем корректно работающий lock/update/unlock, потому что операция создания нового объекта уже существует и протестирована. (хотя тут глобальные локи большее говно чем синглтон. хотя если бы все не пытались все в синглтоны пихать, то и с локами проблем бы не было.)
          Ответить
      • Мне ну совсем лень инициализировать синглтоны, поэтому у меня можно встретить подобные конструкции:
        class singletone_user
        {
        public:
        	singletone_user()
        	{
        		if(1 == ++s_ref_count)
        			s_instance = new singletone();
        	}
        	~singletone_user()
        	{
        		if(0 == --s_ref_count)
        			delete s_instance;
        	}
        	static singletone & instance() { return *s_instance; }
        private:
        	static int s_ref_count = 0;
        	static singletone * s_instance = 0;
        }

        К тому же, такой подход в некоторой степени оберегает от ошибок коллег, не чурающихся глобально объявлять экземпляры класса :)
        Ответить
        • > совсем лень инициализировать синглтоны
          Дык если этот синглтон не инициализировать (например в main'е как в моем примере выше), его же распидорасит на *s_instance:)

          P.S. Все, спать пора. singleton_user описывают в каждом месте, где нужен доступ к синглтону. Поэтому все норм (ну в пределах однопоточной проги).
          Ответить
        • P.P.S. Взгляни на паттерн Monostate. Идея схожая, но юзать будет чуточку удобней...
          Ответить
        • не. ну это просто окультуривает синглтоны. коренных проблем не решает.

          "правильный" singletone_user есть на старом проекте. но там он играет роль энкапсуляции поднобностей реализации поддержки многопоточности. типа, схематический код:
          class singletone_user
          {
          public:
          	singletone_user( int user_type )
          	{
          		local_instance = singletone::getInstance()->connect( user_type, pthread_self() );
          		// the handling depends on the user_type
          		// different users/threads might get the same instance (holding reader lock),
          		// or unique instance for destructive operations (while holding the writer lock)
          	}
          	~singletone_user()
          	{
          		singletone::getInstance()->diconnect( local_instance );
          	}
          	singleton& operator() { return *local_instance; }
          private:
          	singletone *local_instance = 0;
          };
          
          void func_uses_the_singletone()
          {
          	singletone_user s(READ_ONLY); // or ADMIN
          	// use the singletone via s() (and potentially pass it to other functions)
          	// return from the function "disconnects" the user from the singleton
          }
          Ответить
          • > or unique instance for destructive operations (while holding the writer lock)
            Хм. А это точно был синглтон?

            Или здесь просто имеется в виду, что во время write лока все read локи отпущены, и код знает, что он единственный, кто в этот момент может работать с данным объектом.
            Ответить
            • да. это синглтон для специальной конфигурации, лежащей в shared memory. большинство приложений ее только читают. но есть пара другая приложений которые могут ее апдейтить или полностью заново перегружать. и для этих приложений singletone_user содержит еще и текущее состояние: потому что на самом деле на все время write lock не берется, потому что тормозит. оно как раз со scoped_lock и началось, а потом увидели что можно слегка извернутся и брать writer_lock только на время замены поинтеров синглтонов.
              Ответить
            • Ну т.е. этот код не утверждает, что писцу создадут новую, уникальную копию объекта. А он всего лишь получит монопольный доступ к тому же самому единственному экземпляру, который достается чтецам.
              Ответить
      • показать все, что скрыто
        ~Клуб знакомств для геев~
             Познакомлюсь с парнем
             Сделаю миньет, подставлю попку парню кавказской внешности.
             Прут наглые хуястые самцы, желательно с большим членом, так как  
             очко сильно раздолблено. Могу принять сразу до 3-х парней.
                Пишите [email protected]  /Тарас/
        Ответить
    • Дьячок-то ваш с хитрецой. А зачем вообще нужны синглтоны? В википедии как всегда мусор, точнее, какие-то извращения с TObject, но я не осилил.
      Ответить
      • Просто по правилам хорошего стиля считается что глобальные переменные зло, вместо них делают синглтоны.
        Ответить

    Добавить комментарий