уничтожение объекта-одиночки

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

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

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

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

 Martin York24 сент. 2010 г., 20:09
@jalf: Вы тогда по-другому истолковали этот вопрос для меня. Для меня ОП спрашивает, как убедиться, что одноэлементный объект правильно разрушен (то есть его деструктор правильно вызван и ресурсы освобождены). И как убедиться, что этот процесс реализован компилятором так, что пользователю сингелтона не нужно делать это вручную.
 jalf24 сент. 2010 г., 19:58
@Als: вам нужно иметь возможность явно уничтожить одноэлементный объект, или вам просто нужно убедиться, что его деструктор вызывается до завершения процесса?
 James McNellis24 сент. 2010 г., 18:56
Лучший обычно нет никаких синглетонов вообще; тогда вам не нужно уничтожать никаких синглетонов :-)
 jalf24 сент. 2010 г., 19:57
@Martin: но синглтон может, в значительной степени по определению, не быть явно уничтожен (так как это нарушит инвариант, который должен обеспечивать синглтон, чтоодин экземпляр выходит). Поэтому, если вы хотите ответить на конкретный вопрос, единственный правильный ответ - «вы этого не сделаете». И если мы отступим и начнем рассматривать варианты синглетонов, то имеет смысл только спросить, действительно ли что-то синглтоноподобное является правильным решением.
 Alok Save25 сент. 2010 г., 17:54
@jalf, Martin - Спасибо за комментарий. Я согласен, что лучше избавляться от синглетонов, а не нет, но в некоторых случаях это невозможно (некоторые уже существующие унаследованные коды и т. Д.), Поэтому вопрос в том, ДОЛЖЕН ли БЫТЬ использоваться синглетон, как обеспечить его безопасное уничтожение.
 Martin York24 сент. 2010 г., 19:40
Да, синглтоны сложны в использовании и вызывают проблемы, если вы не осторожны. Но давайте ответим на заданный вопрос. Если мы хотим обсудить достоинства одиночных игр, которые должны быть сделаны, это собственный конкретный вопрос.
 Steve Townsend24 сент. 2010 г., 19:10
Для справки о том, почему "Одинокие злые", читайтеlostechies.com/blogs/scottdensmore/archive/2009/08/13/... и его предшественник, который связан оттуда.
 Mike Seymour24 сент. 2010 г., 18:57
Удаление исходного и заголовочного файлов должно помочь. Тогда придумайте дизайн, который не использует синглтоны.
 Martin York24 сент. 2010 г., 20:58
Отвечая на другой вопрос, является ли синглтон хорошей идеей. Для новичков никогда. Для экспертов я вижу, как он используется, но в этом нет необходимости. И сделать это правильно это нельзя сделать изолированно. Чтобы заставить TDD работать, синглтон должен быть сгенерирован на фабрике, а фабрика должна быть частью подключаемого интерфейса (как вы можете видеть все нетривиально, чтобы делать правильно, но это можно сделать).

Ответы на вопрос(6)

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

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. Имейте в виду, что если вы сделаете это, у вас также может быть глобальная переменная, поскольку вы уничтожаете основное преимущество синглетонов над глобальными переменными (ленивая инициализация). Не то, чтобы глобальные переменные были намного лучше, чем синглтоны.

Пример гвардии

// 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

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

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

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

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;
  }
}
 Fanatic2325 сент. 2010 г., 08:06
@filipe Спасибо, исправил это.
 InsertNickHere24 сент. 2010 г., 19:28
Не используйте статический экземпляр MySingleton; вернуть экземпляр в эти дни?
 Alok Save24 сент. 2010 г., 19:11
@Arpan - Спасибо! Но реальная проблема, я думаю, заключается в том, чтобы эти методы уничтожения вызывались в самом конце, когда ни один ресурс больше не нуждается в синглтоне. Я пытаюсь найти хорошие решения для этой проблемы.
 filipe24 сент. 2010 г., 19:08
Вы не имеете в виду «если (экземпляр)»?
 Fanatic2325 сент. 2010 г., 08:15
@Als Есть разница между тем, когда код не обращается к синглтону, и когда программа заканчивается. Не уверен, когда вы хотите, чтобы синглтон был уничтожен. Просьба уточнить.
 Arkadiy24 сент. 2010 г., 19:21
Это может привести к нескольким экземплярам вашего синглтона в настоящих многопроцессорных системах с кэш-памятью для каждого процессора или даже в зависимости от того, как компилятор использует регистры. Вы должны убедиться, что «экземпляр» приходит из основной памяти, прежде чем проверять, например,! = 0. Это одна из функций мьютекса на современных машинах. Эта ссылка (cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html) в основном о Java, но также работает и на C ++.

Не создавайте это в первую очередь!

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

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

 bigxiao05 июн. 2018 г., 17:19
@jalf Singleton не означает, что должен быть экземпляр, но не более одного экземпляра.
 Alok Save24 сент. 2010 г., 19:07
Я понимаю подводные камни, связанные с использованием синглтона, и, как многие из вас упоминали, этого следует избегать, но если нужно использовать синглтон, то какие есть варианты? оберните это в умный указатель, который использует подсчет ссылок, может быть вариант, я ищу возможные решения или обходные пути.
 jalf24 сент. 2010 г., 19:46
@ Алс: почему вы должны использовать синглтон? Синглтон специальноне позволит вам уничтожить его (потому что тогда у вас больше не будет ни одного экземпляра)
 Anthony Williams24 сент. 2010 г., 19:10
Если вы храните указатель экземпляра в интеллектуальном указателе со статической продолжительностью хранения, он будет уничтожен при выходе из программы.

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

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

GlobalThing *global_thing = 0;

// ...

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

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

Это дает вам:

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

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

Порядок инициализации глобалов. Но это не похоже наСтатическая инициализация (и разрушение) заказа Fiascoпотому что этот метод дает вам преимущество определения порядка инициализации и уничтожения глобалов (если вы определите их все так).Что-то еще, я уверен.
 Nick25 сент. 2010 г., 09:53
Одной из вещей «что-то еще» было бы, если что-либо ссылается на глобальный указатель перед основными запусками, например: инициализация другого глобального / статического объекта. Это не значит, что они также хороши в архитектурном плане, но это другой случай, который происходит в реальном коде ...
 Red XIII23 янв. 2011 г., 21:38
Это звучит как разумный способ превратить Синглтон в глобальную переменную «с хорошим поведением» (я не верю, что говорю это).

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

Ваш ответ на вопрос