Подтвердить что ты не робот

Синглтон-деструкторы

Должны ли объекты Singleton, которые не используют экземпляры экземпляра/ссылки, считаться утечками памяти в С++?

Без счетчика, который вызывает явное удаление экземпляра singleton, когда счетчик равен нулю, как объект удаляется? Убирается ли она ОС при завершении приложения? Что, если этот Синглтон выделил память в куче?

Вкратце, мне нужно вызвать деструктор Singelton или я могу полагаться на его очистку, когда приложение завершается?

4b9b3361

Ответ 1

Вы можете полагаться на очистку операционной системы.

Тем не менее, если вы находитесь на мусорном собрании с финализаторами, а не с деструкторами, вы можете захотеть иметь изящную процедуру выключения, которая может полностью закрыть ваши синглтоны напрямую, чтобы они могли освободить любые критические ресурсы в случае использования системных ресурсов, которые не будут правильно очищены, просто закончив приложение. Это связано с тем, что в большинстве языков финализаторы работают на основе "лучших усилий". С другой стороны, очень мало ресурсов, которые нуждаются в такой надежности. файловые дескрипторы, память и т.д. все возвращаются к ОС чисто независимо.

Если вы используете одиночный лингтон, который лениво распределен (например, с идиомой блокировки с тройной проверкой) на языке, таком как С++, с реальными деструкторами, а не с финализаторами, тогда вы не можете полагаться на его деструктор, вызываемый во время выключения программы. Если вы используете один статический экземпляр, деструктор будет запускаться после выполнения основных завершений в какой-то момент.

Независимо от того, когда процесс завершается, вся память возвращается в операционную систему.

Ответ 2

Как часто, "это зависит". В любой операционной системе, достойной имени, когда ваш процесс завершается, все память и другие ресурсы, используемые локально внутри процесса, будут выпущены. Вам просто не нужно беспокоиться об этом.

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

RAII поможет вам здесь. Если у вас есть такой сценарий:

class Tempfile
{
Tempfile() {}; // creates a temporary file 
virtual ~Tempfile(); // close AND DELETE the temporary file 
};

Tempfile &singleton()
{
  static Tempfile t;
  return t;
}

... тогда вы можете быть уверены, что ваш временный файл будет закрыт и удален, однако ваше приложение будет завершено. Однако это НЕ является потокобезопасным, и порядок удаления объекта может быть не таким, каким вы ожидаете или требуете.

однако, если ваш синглтон реализован, как ЭТО

Tempfile &singleton()
{
  static Tempfile *t = NULL;
  if (t == NULL)
    t = new Tempfile(); 
  return *t;
}

... тогда у вас другая ситуация. Память, используемая вашим tempfile, будет восстановлена, но файл НЕ будет удален, потому что деструктор не будет вызван.

Ответ 3

Вы должны явно очистить все свои объекты. Никогда не полагайтесь на ОС, чтобы очистить вас.

Где я обычно использую singleton - это инкапсулировать управление чем-то вроде файла, аппаратного ресурса и т.д. Если я неправильно очищу это соединение, я могу легко протечь системные ресурсы. При следующем запуске приложения он может выйти из строя, если ресурс по-прежнему заблокирован предыдущей операцией. Другая проблема может заключаться в том, что любая финализация, такая как запись буфера на диск, может не произойти, если она все еще существует в буфере, принадлежащем экземпляру singleton.

Это не проблема с утечкой памяти - проблема в том, что вы можете утечка ресурсов, отличных от памяти, которые могут быть не так легко восстановлены.

Ответ 4

Каждый язык и среда будут отличаться, хотя я согласен с @Aaron Fisher в том, что одноэлемент имеет тенденцию существовать на протяжении всего процесса.

В примере С++, используя типичную синглтонную идиому:

Singleton &get_singleton()
{
   static Singleton singleton;
   return singleton;
}

экземпляр Singleton будет создан при первом вызове функции, и тот же экземпляр будет иметь деструктор, вызываемый во время фазы статического статического деструктора при выключениях программы.

Ответ 5

Любой вид распределения, за исключением разделяемых памяти, автоматически очищается операционной системой, когда процесс завершается. Поэтому вам не нужно явно обращаться к деструктору singleton. Другими словами, никаких утечек...

Кроме того, типичная реализация singleton, такая как Meyers 'Singleton, не только потокобезопасна во время инициализации при первом вызове, но также гарантирует грациозное завершение, когда приложение выходит (вызывается деструктор).

В любом случае, если приложению отправляется сигнал unix (т.е. SIGTERM или SIGHUP), поведение по умолчанию заключается в завершении процесса без вызова деструкторов статических выделенных объектов ( одиночки). Чтобы преодолеть эту проблему для этих сигналов, можно распоряжаться обработчиком, вызывающим exit, или вывести выход таким обработчиком - signal(SIGTERM,exit);

Ответ 6

Как вы создаете объект?

Если вы используете глобальную переменную или статическую переменную, вызывается деструктор, предполагая, что программа выйдет нормально.

Например, программа

#include <iostream>

class Test
{
    const char *msg;

public:

    Test(const char *msg)
    : msg(msg)
    {}

    ~Test()
    {
        std::cout << "In destructor: " << msg << std::endl;
    }
};

Test globalTest("GlobalTest");

int main(int, char *argv[])
{
    static Test staticTest("StaticTest");

    return 0;
}

Распечатывается

In destructor: StaticTest 
In destructor: GlobalTest

Ответ 7

Это фольклор, чтобы освободить выделение глобальной памяти явно до того, как приложение завершится. Я полагаю, что большинство из нас это делает по привычке и потому, что мы плохо себя чувствуем, чтобы "забыть" о структуре. В мире C это закон симметрии, что какое-либо распределение должно иметь место для освобождения. Программисты С++ думают иначе, если они знают и практикуют RAII.

В старые добрые времена, например, У AmigaOS были утечки REAL. Когда вы забыли освободить память, он НИКОГДА не станет доступен снова, пока система не будет reset.

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

Ответ 8

A singleton будет одним из экземпляров вашего объекта. Вот почему он не требует счетчика. Если он будет существовать для длины вашего приложения, то деструктор по умолчанию будет в порядке. В любом случае память будет восстановлена ​​операционной системой, когда процесс завершится.

Ответ 9

Зависит от вашего определения утечки. Unbound memory увеличивается утечка в моей книге, singleton не несвязан. Если вы не указали подсчет ссылок, вы намеренно сохраните экземпляр в активном состоянии. Не случайно, не утечка.

Дескриптор оболочки singleton должен удалить экземпляр, он не является автоматическим. Если он просто выделяет память и ресурсы ОС, нет смысла.

Ответ 10

Любая память кучи, выделенная вашим процессом и не освобожденная (удаленная), будет восстановлена ​​ОС. Если вы используете наиболее распространенную реализацию singleton, которая использует статические переменные, это также будет очищено от завершения вашего приложения.

* Это не значит, что вы должны идти по новым указателям и никогда не чистить их.

Ответ 11

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

class Singleton{
...
   friend class Singleton_Cleanup;
};
class Singleton_Cleanup{
public:
    ~Singleton_Cleanup(){
         delete Singleton::ptr;
     }
};

Создайте класс очистки после запуска программы, а затем, выйдя из деструктора, будем называть очистку синглтона. Это может быть более подробным, чем позволить ему перейти в операционную систему, но оно следует принципам RAII и в зависимости от ресурсов, выделенных в вашем одноэлементном объекте, это может быть необходимо.