Освобождение выделенной памяти

Это хорошая практика? Или я должен просто заменить блок кода между { и } функцией? Его можно использовать повторно (я признаю), но моя единственная мотивация для этого — освободить colsum, поскольку он огромен и не требуется, чтобы я мог освободить выделенную память.

 vector<double> C;
 {
  vector<double> colsum;
  A.col_sum(colsum);
  C = At*colsum;
 }
 doSomething(C);

person Jacob    schedule 14.07.2010    source источник
comment
Насколько я понимаю, деконструктор переменной не обязательно вызывается до тех пор, пока функция не завершится (даже если она выходит за пределы области видимости), поэтому это может даже не выполнять то, что вы намеревались.   -  person BlueRaja - Danny Pflughoeft    schedule 14.07.2010
comment
Для тех, кто считает, что это не работает, см. title="какова цель анонимных блоков в языках стиля c"> stackoverflow.com/questions/500006/   -  person bshields    schedule 14.07.2010
comment
Неважно, я думаю, я ошибаюсь; не гарантируется освобождение памяти для самого vector<double> colsum до выхода из функции, но его деструктор гарантированно вызывается, как только выходит из области видимости.   -  person BlueRaja - Danny Pflughoeft    schedule 14.07.2010
comment
@BlueRaja: Это именно то, что я хочу сказать. Мой вопрос в том, должен ли я написать для этого функцию или это считается хорошей практикой программирования.   -  person Jacob    schedule 14.07.2010


Ответы (5)


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

person bshields    schedule 14.07.2010
comment
+1: за предложение разбить его в любом случае - делает код более пригодным для повторного использования/читабельным :-) - person Jon Cage; 14.07.2010
comment
@bshileds: Основная цель, как указано в вопросе, - принудительное освобождение вектора. Это то, что вы имели в виду (кажется, это из ваших комментариев)? - person Jacob; 14.07.2010
comment
@Jacob Я понимаю ваше намерение, и я говорю, что это правильный способ сделать это, более чистый, чем использование функции swap, как было предложено другими ответами, потому что он использует RAII. У него есть свое место, особенно для обертывания кода с использованием объекта Mutex или чего-то подобного. НО вам просто нужно быть осторожным, потому что, используя скобки, вы признаете, что у вас есть этот дополнительный набор переменных, которые вы хотите сохранить отдельно и использовать в их собственной области для выполнения некоторой промежуточной обработки. У вас должна быть веская причина не делать этот блок своей собственной функцией, потому что он определенно пахнет таковой. - person bshields; 14.07.2010

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

ИЗМЕНИТЬ

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

/РЕДАКТИРОВАТЬ

Но в чем смысл? Похоже, вы преждевременно занимаетесь оптимизацией.

Если вы хотите реорганизовать свой код, делайте это ради ясности, а не производительности.

person Cogwheel    schedule 14.07.2010
comment
Не совсем. Когда colsum выходит из области видимости, он освобождает связанную с ним память. - person Jacob; 14.07.2010
comment
Вопрос немного неточен, но очевидно, что речь идет о динамически выделяемой памяти, а не об используемой памяти стека. В зависимости от размера вектора это может быть очень серьезной проблемой использования памяти кучи, я не думаю, что вы можете автоматически списать это как преждевременную оптимизацию. - person bshields; 14.07.2010
comment
Если оставить выделенную память до завершения функции, это ничего не повредит. Если вы обнаружите, что на самом деле сталкиваетесь с ситуациями с нехваткой памяти, значит, ваша оптимизация созрела. jMerliN также делает хорошее замечание. Я не уверен, что есть хоть какая-то гарантия того, что освобождение произойдет в закрывающей фигурной скобке. В любом случае он может дождаться окончания функции. - person Cogwheel; 14.07.2010
comment
Есть способы освободить векторную память без этих хлопот (например, std::vector<double>().swap(colsum);). Я написал ответ на этот счет. - person David Rodríguez - dribeas; 14.07.2010
comment
Нет, поведение с заданной областью четко определено. Переменная выходит из области видимости и объект уничтожается, память освобождается. - person bshields; 14.07.2010
comment
@bshields: (Брук?) Спасибо! Есть ли что-нибудь в стандарте на этот счет? - person Jacob; 14.07.2010

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

Кроме того, я не уверен, что в ISO указано, что реализация должна извлекать переменную подобласти из стека.

person Justin Summerlin    schedule 14.07.2010

Как указывали другие, векторная память не выделяется в стеке. Если вы хотите освободить эту память раньше, общая идиома:

vector<double> C;
vector<double> colsum;
A.col_sum(colsum);
C = At*colsum;
    std::vector<double>().swap(colsum);
doSomething(C);

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

Обратите внимание, что colsum.resize(0) и colsum.clear() не нужно освобождать доступную память, и во многих случаях они не будут предполагать, что если вектор вырос до этого размера раньше, есть вероятность, что он сделает это снова.

person David Rodríguez - dribeas    schedule 14.07.2010
comment
Но лучше ли это, чем использование фигурных скобок для ограничения области? Хотя трюк с обменом хорошо известен, это своего рода окольный способ выразить то, что вы пытаетесь сделать. - person Adrian McCarthy; 14.07.2010
comment
Чтобы очистить вектор, я бы использовал трюк со свопом, поскольку это распространенная идиома, но я согласен, что область действия имеет свои преимущества. Первый из них заключается в том, что идентификатор можно использовать повторно, а второй заключается в том, что он будет работать для типов, где нет swap эквивалента (например, блокировок с ограниченной областью действия){ lock(mutex); .... } - person David Rodríguez - dribeas; 15.07.2010

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

person 5ound    schedule 14.07.2010