2010-03-11 3 views
21

Я бы хотел, чтобы мой класс имел статический указатель на динамически выделенную область памяти. Я понимаю, как его инициализировать - в моем случае я инициализирую его, когда ему нужен первый объект. Тем не менее, я не знаю, когда/где в коде, чтобы освободить его. Я хотел бы освободить его, когда программа завершается.C++ освобождение статических переменных

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

Есть ли более элегантный способ сделать это?

Пожалуйста, дайте мне знать.

Спасибо, JBU

+0

SOUND, как вы пытаетесь изобрести интеллектуальные указатели? –

+0

Эта проблема является одной из проблем, возникающих при реализации синглетов (http://en.wikipedia.org/wiki/Singleton_pattern). Ниже приведен пример примера кода Klaim. Они могут быть хорошей вещью или костылем. Не злоупотребляйте ими. :) – Void

ответ

18

У вас есть два решения здесь:

  1. Не удаляйте его удалить (вы в C++, можно использовать новые и удалять, верно;)) , Почти все ОС сегодня будут «освобождать» память, выделенную приложением, как только она будет закончена. Но это не очень хорошее решение, которое затрудняет обнаружение утечек памяти.
  2. Инкапсулируйте указатель в класс (как член), затем используйте этот класс в качестве типа вашего статического. Таким образом, вы знаете, что деструктор класса будет вызван в конце приложения. Затем вы просто удаляете свои данные в деструкторе, и работа выполняется и очищается. Это сила RAII.

Я предлагаю вам сделать 2, это действительно чистый способ сделать это.


Вот простой пример. Вместо того чтобы делать это

static Thing* things = new Thing(); // or whatever way to initialize, here or in a specific function 

Вы будете делать, что:

class ThingManager // or whatever name you like 
{ 
public: 
    ThingManager(Thing* thing) : m_thing(thing) { }//or create it here? whatever solution suits your way of creating the data 

    ~ThingManager() { delete m_thing; } // THAT's the important part! 

    Thing* instance() const { return m_thing; } // or whatever accessor you need, if you need one 

private: 
    Thing* m_thing; 
}; 

, а затем

static ManagedThing thing; // now i can access it via thing.instance() 

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

Это написано, чтобы дать вам представление о том, как вы можете это сделать.

+0

Извините, я очень новичок в C++. Когда вы говорите, что «деструктор класса будет вызван в конце приложения», вы говорите, что есть деструктор объекта и деструктор статического класса? Кроме того, что такое RAII? – jbu

+0

RAII: http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization Вы должны узнать о функциях по умолчанию для всех классов. – Klaim

+4

RAII - неудачный термин, потому что он не очень описателен; см. http://en.wikipedia.org/wiki/RAII –

2

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

0

я бы определить статический счетчик в классе отслеживать подсчет экземпляров объектов как деструктор получить Казнить уменьшаем счетчик и если счетчик == 0 освободить память тоже .. так же, как вы

6

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

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

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

+0

Спасибо за ответ. Я всегда думал, что утечка памяти заставит ОС удерживать резервную/незакрепленную память даже после завершения программы. – jbu

+1

@jbu: Это было бы не очень хорошая ОС, если бы это было так. ;) –

+2

Хотя это будет маскировать другие утечки памяти с помощью некоторых средств обнаружения утечки памяти, поэтому в любом случае это не рекомендуется. – Klaim

14

Бросьте его в умном указателе. Она будет иметь статический срок службы и будет уничтожена после main возвращений:

static std::auto_ptr<T> thePointer; 

Другого варианта, чтобы зарегистрировать свою собственную atexit функцию:

// static 
void YourClass::freePointer(void) 
{ 
    delete getPointer(); 
} 

// static 
T* YourClass::getPointer(void) 
{ 
    if (!thePointer) 
    { 
     thePointer = new T; 
     atexit(freePointer); 
    } 

    return thePointer; 
} 

который будет иметь тот же эффект. Еще один вариант, который вы уже упоминаете, - сохранить статический счетчик. Обратите внимание, что вы можете эффективно обернуть это довольно эффективно.

+1

Alexandrescu использует 'atexit' в реализации своего' Loki :: Singleton'.Таким образом, он гарантирует, что методы, которые освобождают указатель, также сбрасывают его состояние на «0», чтобы его можно было перераспределить при необходимости (случай политики времени «Феникс»). Лично я считаю, что 'auto_ptr' или даже лучше' unique_ptr' гораздо меньше проблем. –

+0

Это нехорошо, существует только небольшое ограниченное количество функций очистки at_exit, иногда до 32 (минимум, определенный в стандарте) – Lothar

Смежные вопросы