2009-06-08 2 views
5

Я очень запутался в управлении памятью по отношению к векторам и мог бы сделать некоторые основные объяснения.Управление памятью и вектором C++

У меня есть программа, которая использует большие векторы. Я создал векторы с нового оператора и выпустить их в конце программы с удалить, чтобы память обратно.

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

У меня также есть некоторые другие крупные векторы, которые я назначу без нового ключевого слова. Я читал, что они будут созданы в куче, но не должны быть освобождены в любом случае, так как управление памятью обрабатывается «под капотом». Однако я не уверен, что это так, поскольку каждый раз, когда я запускаю свою программу, я теряю ОЗУ.

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

И я полагаю, третий вопрос, который только подрессоренный на ум, если векторы автоматически создаются в куче, почему бы вы когда-либо использовать нового ключевым слово с ними? Спасибо за чтение, ben

+2

«Каждый раз, когда я запускаю свою программу, я теряю RAM», вы имеете в виду, что «моя доступная RAM становится меньше, пока я не выйду из программы», или «моя доступная ОЗУ становится меньше даже после выхода из программы, и она становится еще меньше в следующий раз, когда я забегу, до одного дня у меня останется совсем нет ОЗУ "? –

+0

Я отвечаю на вопрос Макса. Windows, я считаю, фактически не выгружает завершенные программы, если это не нужно. Таким образом, они запускаются быстрее после первого раза. –

+0

«И я полагаю, что третий вопрос, который только что возник в сознании, заключается в том, что если в кучу автоматически создаются векторы, почему бы вам использовать новое ключевое слово с ними?» Вам нужно будет сделать это, только если вам нужно передать вектор в точку за пределами текущей области. Это относительно редко на практике. – rlbond

ответ

13

Я подозреваю, что ваши вопросы касаются std :: vector < T> (в отличие от массива T []).

  1. Когда приложение по какой-либо причине выходит из строя или прерывается, ОС восстанавливает память. Если нет, вы используете по-настоящему редкую ОС и обнаружили ошибку.
  2. Вам нужно различать память, используемую самим вектором, и память его содержащихся объектов. Вектор может быть создан в куче или в стеке, как вы отметили, память, которую он выделяет для содержащихся в нем элементов, всегда находится в куче (если вы не предоставите свой собственный распределитель, который сделает что-то еще). Память, выделенная вектором, управляется реализацией вектора, и если вектор разрушается (либо потому, что он выходит за пределы области действия для вектора в стеке, либо потому, что вы удаляете вектор в куче), его деструктор гарантирует, что все память освобождается.
+1

Большинство встроенных ОС и многих RTOS не очищают ресурсы при сбое процесса. –

3

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

«Каждый раз, когда я запускаю свою программу, я теряю RAM» должен быть вызван каким-то другим эффектом - как вы это измеряете?

Как почему вы бы использовать «новый» - две причины:

  • Вы хотите контролировать, когда они будут освобождены
  • Вы хотите, чтобы они сохраняются после текущих выходов функции.
+1

Тот же комментарий, что и Тобиас.Большинство встроенных ОС и много RTOS не очищают ресурсы при сбое процесса. –

+0

+1 для указания того, что многие не понимают. Диспетчер виртуальной памяти - это роскошь, которую часто считают само собой разумеющимся. – Void

3

Я полагаю, что вы говорите о std :: vector, а не о языковых массивах.

  1. Когда программа падает, операционная система восстанавливает свою память
  2. станд :: вектор освобождает память, что она выделяет. Если вы храните указатели, они не будут удалены.
  3. Векторы создаются как любая другая переменная, они не находятся в куче только потому, что они являются векторами.
4

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

HOWEVER Вы не можете доверять тому, что вектор vector хранит для очистки после себя. То, что нужно очистить, может быть чем-то, что сохраняется за пределами вашего приложения. Если его память, это не беспокойство. Если убедиться, что все теги XML закрыты, то ОС не сможет вам помочь.

Например, что если у вас есть вектор некоторых шатких блокировок объекта, как это:

class CLock 
    { 
    public: 
     CLock() {} 
     ~CLock() {} 

     void Lock(...) {...} 

     void Unlock(...) {...} 
    }; 

    std::vector<CLock> myLockVec; 

Как бы ваш вектор знать ЧАСЫ, чтобы разблокировать все, когда его сделали? Вектор не создан, чтобы знать о замках.

Это, по существу, та же ситуация, имеющий вектор указателей:

std::vector<int*> myIntVec; 

Как вектор знать, какие указатели здесь были удалены и NULL'd, и какие из них действительно есть? Возможно, некоторые из них были удалены и установлены на ваше особое значение 0xdeadbeef, что означает удаление.

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

Решение должно быть уверенным, что любой векторный HOLDS должен отвечать за его очистку. Это называется RAII - Назначение ресурсов - это инициализация, что более важно здесь, уничтожение ресурсов - это освобождение. При использовании нашего примера CLOCK, ответ очевиден, обязательно откройте его, когда мы закончите!

class CLock 
{ 
     ... 
     ~Clock() 
     { 
      if (locked) 
      { 
       Unlock(); 
      } 
     } 
} 

Но с указателями его не так очевидно. Решение состоит в том, чтобы обернуть указатель в классе smart_ptr. Наиболее плодотворными являются boost family of smart poniters.

class CSmartPointer<T> 
{ 
     CSmartPointer(T* rawPtr) 
     { 
     m_ptr = rawPtr; 
     } 

     ~CSmartPointer() 
     { 
     delete m_ptr; 
     } 
} 

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

1

Для «потерянной памяти», что @RichieHindie говорит.

Что касается второго вопроса:

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

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

+0

Необработанные исключения (те, которые приводят к тому, что среда выполнения в конечном итоге вызывает terminate()), не могут вызывать деструкторы. В этом случае поведение разворачивания стека определяется реализацией. – ASk

8

new ID: номер: new Для создания векторов. Просто положите их в стек.

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

class HeapInt 
{ 
    public: 
     HeapInt(int i) {ptr = new int(i);} 
     ~HeapInt() {delete ptr;} 
     int& get() {return *ptr;} 
    private: 
     int* ptr; 
}; 

int main() 
{ 
    // this code DOES NOT leak memory 
    std::vector<HeapInt> vec; 
    for (int i = 0; i < 10; ++i) 
    { 
     HeapInt h(i); 
     vec.push_back(h); 
    } 
    return 0; 
} 

Даже если основной() бросает исключение, память не теряется. Тем не менее, этот код делает памяти утечки:

int main() 
{ 
    // this code though, DOES leak memory 
    std::vector<int*> vec; 
    for (int i = 0; i < 10; ++i) 
    { 
     int* ptr = new int(i); 
     vec.push_back(ptr); 
    } 
    // memory leak: we manually invoked new but did not manually invoke delete 
    return 0; 
} 
+0

Это не всегда работает. –

+4

Да, но человек, задающий вопрос, явно не знает, что векторы должны УСТРАИЛЬНО быть помещены в стек. – rlbond

+0

Как будет второй пример утечки памяти? программа заканчивается, и ОС восстанавливает память, или мне не хватает чего-то ужасно важного для управления памятью. –

2

Один из нас двоих есть немного запутался здесь.

Если вы используете std :: vector, вам не нужно вручную выделять память для своих элементов. Дополнительное пространство будет автоматически выделяться при необходимости, когда вы будете делать push_back(). Если вам по какой-то причине требуется все свободное место, вы можете вызвать reserve(). В любом случае память автоматически освобождается для вас, когда вектор разрушается.

Если вы делаете новый std :: vector, вы получаете указатель на вектор. Это ничем не отличается от вызова нового в любом другом классе. Вы создаете указатель на объект этого класса, и он будет разрушен при вызове delete. Если вам не нравится это поведение, попробуйте создать свой вектор в стеке.

1

Другой сценарий, не упомянутый в отношении того, когда вы хотите использовать «новое», в некоторых случаях, когда вектор является переменной-членом класса. NULL может использоваться как дополнительный семафор, например, во время создания по требованию; Кроме того, если использование вектора редко заселено на вашем классе, то даже создание одного, если это действительно необходимо, спасет вашу память за счет дополнительного 4-байтового штрафа во всех экземплярах, а также от вреда во время выполнения указателя.

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