уничтожение объекта-одиночки - PullRequest
4 голосов
/ 24 сентября 2010

Какой лучший способ уничтожить одноэлементный объект?

корпус A: однопоточная среда
вариант B: многопоточная среда

Примеры фрагментов (если есть) будут действительно полезны.

[РЕДАКТИРОВАТЬ] У меня нет конкретного варианта использования, я просто пытаюсь понять, что ЕСЛИ ВСЕМ синглтон нужно использовать, как правильно его уничтожить. Как я понимаю, из комментариев возможны 2 сценария:
1. Уничтожить синглтон, когда к нему не обращается код (используйте умные указатели, которые позаботятся о том, чтобы уничтожить объект самостоятельно с помощью RAII)
2. Уничтожить одноэлементный файл при выходе из программы независимо от того, удерживался ли какой-либо код в одноэлементном блоке. (явно уничтожить, удалив экземпляр перед главным выходом)

Ответы [ 6 ]

9 голосов
/ 24 сентября 2010

Во-первых, не создавайте его!

Серьезно, я настоятельно рекомендую вам пересмотреть свой выбор синглтона, особенно в многопоточной среде.Вместо этого просто создайте экземпляр в main() и передайте его вниз по иерархии вызовов туда, где он необходим.

Вы можете использовать что-то вроде shared_ptr, чтобы гарантировать, что объект останется, пока никто не понадобится.больше.

2 голосов
/ 25 сентября 2010

Может быть в состоянии использовать atexit () , если вам нужна только очистка при успешном завершении работы.

1 голос
/ 24 сентября 2010

Если вы собираетесь использовать глобальный, я предпочитаю что-то вроде этого:

class GlobalThing{ /* ... */ };

GlobalThing *global_thing = 0;

// ...

int main(){
  GlobalThing gt(/* ... */);
  global_thing = >

  // create threads
  // ...
  // kill threads
}

Это дает вам:

  1. Легко идентифицируемое время жизни глобального объекта.
  2. Очистка ресурсов в типичной RAII манере.
  3. Вышеуказанные пункты означают, что он работает в многопоточной среде, не беспокоясь о блокировках и т. Д., Поскольку никакие потоки не будут существовать до или после жизни gt. Ну, в некоторых средах вы можете выйти из main (), и другие потоки будут продолжать работать, но это ужасный способ архитектуры вашей программы по разным причинам.

О чем вам еще нужно беспокоиться:

  1. Порядок инициализации глобалов. Но это не похоже на статический порядок инициализации (и уничтожения) Fiasco , потому что этот метод дает вам преимущество определения порядка инициализации и уничтожения глобалов (если вы определите их все таким образом).
  2. Что-то еще, я уверен.
1 голос
/ 24 сентября 2010

Оставляя в стороне вопрос о том, хорошая ли это идея.
Что мы должны сделать в отдельном вопросе!

class S
{
    private:
        S() {}                // private constructor
        S(S const&);          // Undefined copy constructor
        S& operator(S const&) // Undefined assignment operator

    public:
        static S& getInstance()
        {
            /*
             * It is guaranteed to be built on first use
             * and correctly destroyed at the end of the application 
             */
            // Need guard for multi-threaded systems (but not on gcc)
            MULT_THREAD_GUARD;
            static S theOnlyInstance;
            return theOnlyInstance;
        }
};

Многопоточная инициализация объекта - единственная реальная проблема.Вы можете справиться с этим двумя способами.

  • Вы можете либо поставить GUARD, чтобы убедиться, что только один поток может войти в метод getInstance () при выполнении многопоточных сборок (если вы используете gcc, это не так.Требуется, поскольку он автоматически устанавливает требуемый код, чтобы гарантировать, что объект инициализируется только один раз.
  • Другой метод - просто убедиться, что экземпляр инициализирован перед созданием каких-либо потоков.Для этого просто вызовите getInstance () в main.Имейте в виду, что если вы сделаете это, у вас также может быть глобальная переменная, поскольку вы уничтожаете основное преимущество синглетонов над глобальными переменными (ленивая инициализация).Не то чтобы глобальные переменные были намного лучше, чем синглтоны.

Пример Guard

// Then in your platform agnostic header file
#ifndef MULTI_THREAD
#define MULT_THREAD_GUARD       /* Nothing needed in single threaded code */
#else
#if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 3 ) && (__GNUC_MINOR__ > 1)))
#define MULT_THREAD_GUARD        /* Nothing required for GCC 3.2 onwards */
#elif defined(YOUR_COMPILERS_MACRO)
#define MULT_THREAD_GUARD        do { /* Put compiler lock code here */ } while (false)
#else
#error "ADD MULTI Thread GUARD for you compiler here"
#endif
1 голос
/ 24 сентября 2010

Обратная реакция против чрезмерного использования Singletons в последнее десятилетие, похоже, в грубом здоровье, но они не совсем злые или неоправданные ... программирование - это компромиссы и практичность, и ее трудно обобщить (обычно;,Обязательно пересмотрите дизайн и посмотрите, сможете ли вы с пользой избавиться от них, но если нет - пусть будет так.

В любом случае, если вы хотите понять компромиссы, вы не можете добиться большего успеха, чем начатьпрочитав «Современный дизайн C ++» Александреску, в котором глава посвящена альтернативам для синглетонов.По сути, вы задаете здесь глупый вопрос, потому что мы не знаем, какие эксплуатационные ограничения имеют ваши синглтоны (ы) ... какие потенциальные взаимодействия, какие ресурсы им может понадобиться и могут ли они быть вновь открыты после закрытияитд. Так, выкладывай или соглашайся на глупые ответы; -P.

1 голос
/ 24 сентября 2010

В многопоточном,

void Singleton::Destroy() 
{
  if (instance) { 
      pthread_mutex_lock(&lock);
      if (instance) { 
          delete instance;
          instance = 0x0;
      }
      pthread_mutex_unlock(&lock);
  }
}

В однопоточном:

void Singleton::Destroy() 
{
  if (instance) { 
      delete instance;
      instance = 0x0;
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...