Удаление вектора из памяти c
И в конце программы я хочу чтобы деструктор класса, который хранит в себе vector удалил все его элементы, и если честно не получается, может кто подскажет?
Решение
Нет не проще так как в противном случае вы память не освободите. Имейте ввиду ни один из методов vector не урезает выделенную память акромя shrink_to_fit. Но эта приблуда только в C++11. Хотя стоит обратить внимание, что при вызове clear для основного вектора память выделенная внутренними векторами все-таки освободится.
Проще если не нужно физическое освобождение памяти. Если нужно чтобы память была отдана системе, то нужно делать как написал Ilot, либо искать или писать какой-то другой контейнер вместо вектора.
Добавлено через 2 минуты
Забыл добавить, в твоем случае память не освобождается только у внешнего вектора. У внутренних векторов при вызове clear() у внешнего вызываются деструкторы и память таки освобождается.
не понял. почему это? Ну вызвал я Clear() вышел за скоуп и всё!, по идее память то должна была освободится? Или нет? :-)
Тут проще было бы нарисовать
Это такая оптимизация, пока вектор живет и ты производишь с ним разные операции внутренне выделяемая память не освобождается.
Создали вектор
Добавили в вектор 10 чисел
Внутренняя память вектора расширилась на 10 чисел + некоторый запас, size() показывает 10 чисел
Удалили 5 чисел.
Внутренняя память вектора никуда не делать, но size() показывает 5 чисел
Сделали clear()
Внутренняя память осталась прежней, но size() показывает ноль.
Т.е. память освобождается только логически. В расчете на то, что снова потом потребуется.
Прием с swap с пустым вектором как раз позволяет именно освободить внутреннюю память физически, а не логически.
Ну физический она же в итоге тоже по завершению программы освободится, верно же? А в какой момент она физический освободится то? При выходе за scope по идее же? То есть если я в фигурных скобках создал вектор и вызвал КЛИАР, то после выхода из них - всё, память освободилась физический. Верно же? А СВОП нужен, если ты хочешь её физический освободить не выходя за скоп, так?
Физически она освободится деструктором вектора.
Я про другое. Я про освобождение памяти физически в процессе жизни вектора. И Ilot про это же говорил.
Добавлено через 59 секунд
То есть если я в фигурных скобках создал вектор и вызвал КЛИАР, то после выхода из них - всё, память освободилась физический. Верно же?
clear в этом варианте вообще можно не звать. Деструктор все сделает.
скорее это решать аллокатору, а не вектору, так все операции с памятью производятся в векторе через аллокатор.
Вызывает-то deallocate деструктор вектора.
Вот например код из библиотеки моего компилятора. _M_deallocate соответственнно уже дергает функцию аллокатора.
Если аллокатор не заменен на нестандартный, который на самом деле ничего не делает при вызове deallocate, то решает все-таки вектор
Добавлено через 6 минут
Croessmah, Хотя я понял о чем ты. Естественно "физически" - это абстракция. Т.к. есть еще слой C++ runtime, затем OS runtime и там эта память может кешироваться и все такое. Так что говоря "физически" имелось в виду не вообще физически, а компетенция конкретных инструментов. Естественно если аллокатор заменен на какой-нибудь другой, deallocate в котором на самом деле отдает память обратно в пул, то в глобальном смысле слова это НЕ будет "физическим освобождением", но с точки зрения самого вектора - будет. Т.к. в этой связи нет разницы кто закешировал память, самописный аллокатор или С++ runtime, это уже вне компетенции вектора. Он, грубо говоря, сделал все что смог
Векторы аналогичны динамическим массивам с возможностью автоматического изменения размера при вставке или удалении элемента, при этом их хранение автоматически обрабатывается контейнером.
вектор :: ясно ()
Функция clear () используется для удаления всех элементов векторного контейнера, что делает его размером 0.
Синтаксис:
Ошибки и исключения
1. Не имеет исключительной гарантии.
2. Показывает ошибку при передаче параметра.
using namespace std;
// Вектор становится 1, 2, 3, 4, 5
// вектор становится пустым
for ( auto it = myvector.begin(); it != myvector.end(); ++it)
Сложность времени: O (N)
Все элементы уничтожены один за другим.
вектор :: Стирание ()
Функция erase () используется для удаления элементов из контейнера из указанной позиции или диапазона.
Синтаксис:
Ошибки и исключения
1. У него нет гарантии броска без исключения, если позиция действительна.
2. Показывает неопределенное поведение в противном случае.
Извлечение элемента из определенной позиции
using namespace std;
for ( auto it = myvector.begin(); it != myvector.end(); ++it)
Удаление элементов в пределах диапазона
using namespace std;
vector< int >::iterator it1, it2;
for ( auto it = myvector.begin(); it != myvector.end(); ++it)
заявка
Получив список целых чисел, удалите все четные элементы из вектора и напечатайте вектор.
Алгоритм
1. Запустите цикл до размера вектора.
2. Проверьте, делится ли элемент в каждой позиции на 2, если да, удалите элемент и уменьшите итератор.
3. Напечатайте окончательный вектор.
using namespace std;
for ( auto i = myvector.begin(); i != myvector.end(); ++i)
for ( auto it = myvector.begin(); it != myvector.end(); ++it)
Сложность времени: O (N) в худшем случае, когда 1-й элемент удаляется, а O (1) в лучшем случае, когда последний элемент удаляется.
clear () против erase (), когда использовать что?
clear () удаляет все элементы из векторного контейнера, таким образом, его размер равен 0. Все элементы вектора удаляются с помощью функции clear ().
Функция erase (), с другой стороны, используется для удаления определенных элементов из контейнера или ряда элементов из контейнера, тем самым уменьшая его размер на количество удаленных элементов.
Deleaker ищет утечки ресурсов в программах на С++: утечки памяти, дескрипторов, GDI объектов и многие другие.Работает как расширение в Visual Studio, так и в виде отдельного приложения.
среда, ноября 23, 2005
четверг, июня 30, 2005
Выделение памяти под vector
В описании контейнера vector можно встретить такие функции как size и resize , capacity и reserve . С первого взгляда кажется, что половина явно лишняя, ведь размер у вектора может быть только один.
Почему так? Потому что память для вектора выделяется "про запас"(подробнее ниже), и надо уметь управлять и количеством элементов вектора, и количеством памяти, которое он занимает. size и resize - нужны для работы с реальным числом элементов вектора, capacity и reserve - для работы с памятью.
size - выдает количество элементов в векторе
resize - изменяет количество элементов в векторе
capacity - выдает под сколько элементов выделена память
reserve - резервиует память
Вот что сделает код, скомпиленный Visual C++ 6.0:
vector v;
v.push_back(1); //size==1, capacity==1
v.push_back(17); //size==2, capacity==2
v.push_back(23); //size==3, capacity==4
Зачем нужен этот запас?
Допустим, у нас есть вектор из n элементов. Что происходит, когда программист добавляет еще один? Когда есть запасная память, элемент пишется туда. Когда ее нет, выделяется непрерывный кусок памяти достаточный для n*K элементов, где K - коэффицент. В него копируются предыдущие n , добавляется наш новый элемент, старый кусок размером n освобождается. Если бы запаса не было, то память бы выделялась каждый раз при добавлении нового элемента, что страшно неэффективно.
Зачем нужен reserve , если все и без участия программиста так хорошо работает? Это может быть полезно в некоторых ситуациях. Например, знание того, как выделяется память под вектор, можно использовать и в начале, при его задании. Допустим, я точно знаю, что в векторе будет где-то 100-110 элементов. Я сразу же создам вектор размером 110, это поможет избежать перевыделений памяти, положительно скажется на производительности.
vector v;
v.reserve(110);
Это вовсе не означает, что зарезервировано место для 110-ти элементов ровно. Зарезервировано место как минимум для 110 элементов, возможно больше.
Почему обязательно нужно выделять непрерывный кусок памяти, почему при увеличении размера вектора нельзя выделить кусочек где-нибудь еще? Чтобы можно было передавать vector как параметр в функции, которые требуют массив. Например, в какую-нибудь старую библиотечную С-функцию, которая принимает массив и его размер, можно передать вектор, при условии, что он не пустой. Это было сделано специально, чтобы убедить людей пользоваться векторами. Ведь можно продолжать использовать старые библиотеки.
//если где-то описана такая функция
void myPrint(int* v, int vsize);
//ее можно вызвать так
vector v;
v.push_back(2);
v.push_back(3);
myPrint(&v[0], v.size());
Коэффицент К
(Все приведенные ниже рассуждения верны только для first-fit схем выделения памяти, то есть выделяется первый по порядку подходящий кусок)
Что за коэффицент K , который используется при выделении памяти , чему он равен? Так, как у нас там происходит выделение памяти. Новую выделили, прокопировали туда данные, старую освободили. И так несколько раз. Если память идет подряд, то образуется пробел, который можно было бы использовать. Нужно подобрать такой коэффицент, который позволит эти пробелы использовать. Было вычислено, что коэффицент должен быть меньше, чем (1+sqrt(5))/2 . Что примечательно, выражение (1+sqrt(5))/2 - это же "золотое сечение".
Откуда берется это число?
Я видела вот такое доказательство:
Пусть у нас изначально размер вектора был S , S>0 .
После первого перевыделения памяти, он стал K*S .
После второго K*K*S .
Нам нужно, чтобы K*K*S влезло в S+K*S , то есть K*K*S . S>0 , на него можно сократить.
K^2-K-1
Решаем, получаем
K (второй корень, отрицательный, не интересен)
Правильно? Не правильно. Кусок K*S все еще занят, его нельзя использовать.
Нам нужно, чтобы в момент выделения K^(n+1)*S память размером S+K*S+K^2*S+. +K^(n-1)*S была достаточной, чтобы вместить этот K^(n+1)*S . K^n*S все еще занят, мы его использовать не можем. В итоге получаем.
S+K*S+K^2*S+. +K^(n-1)*S или, зная, что S>0
1+K+K^2+. +K^(n-1)
Решать я это не буду, Andrew Koenig считает, что подходящий в данном случае корень (1+sqrt(5))/2 , доверюсь ему.
Если говорить уж совсем точно, то (1+sqrt(5))/2 не совсем правильное число, нужнен коэффицент поменьше. Потому что нужна еще дополнительная память для разных служебных нужд.
В Visual C++ 6.0 взята константа 2. Такой коэффицент использовать пробелы не дает. А вот в Visual C++ 7 уже используется константа 1.5.
Swap Trick
Про выделение памяти ясно. А как с освобождением памяти? Да, при увеличении размера вектора будет выделена память, а когда вектор уменьшается? Нет, она не будет освобождена. Что несколько неудобно, потому что если в векторе было 10000 элементов, а потом их количество уменьшилось до 10 и осталось где-то в таких пределах, то получается что куча памяти пропадает зря. Что можно сделать в такой ситуации? Сделать новый вектор и туда прокопировать старый. Это можно сделать красиво с помощью swap trick.
vector(v).swap(v);
В этой строчке происходит следующее: создается безымянный vector , который инициализируется элементами из v, а потом он меняется с вектором v местами. Это вовсе не гарантирует, что памяти будет выделено ровно столько, сколько нужно, а не больше. Это зависит от реализации. Но, скорее всего, все будет лучше, чем было.
Я читала у Герба Саттера, что swap сохраняет в корректном состоянии все итераторы, ссылки и указатели.
Может я чего-то не понимаю, но у меня получилось вот что.
std::vector v;
std::vector ::iterator it;
vector(v).swap(v);
cout
Updated 23.11.2005 :
Вычитала, что в Visual C++ 7.1 при вызове метода clear() память таки высвобождается. Не могу проверить для 7.1, зато проверила для Microsoft Visual C++ Toolkit 2003. Действительно, память освобождается.
То есть для такого кода:
vector v;
v.reserve(17);
coutv.clear();
cout
Вывод получается следующим
Microsoft Visual C++ Toolkit 2003:
17
0
MSVC++6.0:
17
17
MinGW gcc 3.4.4:
17
17
Стандарт не указывает должна ли освобождаться память при вызове метода clear(), так что все компиляторы здесь действуют по Стандарту.
Освобождение памяти, выделенной под vector
Некоторое время назад я писала про выделение памяти под vector и в конце немного затронула тему высвобождения памяти. В большинстве реализаций освободить память, выделенную под vector, можно только с помощью трюка, известного как swap trick. Недавно я вычитала, что в реализации STL из Visual C++ 7.1 память, выделенная под вектор, высвобождается при вызове метода clear(). 7.1 у меня нет, зато у меня есть Microsoft Visual C++ Toolkit 2003. Действительно, освобождается. Для такого кода:
vector v;
v.reserve(17);
coutv.clear();
cout
Вывод получается такой:
Microsoft Visual C++ Toolkit 2003:
17
0 //действительно, освободилась
MSVC++6.0:
17
17
MinGW gcc 3.4.4:
17
17
Я решила копать дальше. Я всегда считала, что метод clear для последовательных контейнеров эквивалентен erase всего контейнера. Нашла упоминание об этом в документации STL на sgi.com. Вот оттуда выдержка:
a.clear() Equivalent to a.erase(a.begin(), a.end())
Запускаю код:
vector v;
v.reserve(17);
coutv.erase(v.begin(), v.end());
cout
Получаю:
Microsoft Visual C++ Toolkit 2003:
17
17 //не освободилась
MSVC++6.0:
17
17
MinGW gcc 3.4.4:
17
17
Получается, что в случае вышеупомянутого тулкита нет обещанной эквивалентности. Так, а что говорит об этом Стандарт? Вот тут интересный момент. Там нет слова "эквивалентно". Там erase(begin(), end()) приписано к clear() в качестве assertion/note для последовательных контейнеров. А вот требование там одно, что post condition: size()==0. Оно тут выполняется.
Так что MSVC++2003 тут прав.
Я пробовала также v.resize(0). Пробовала удалить все элементы вектора с помощью pop_back'ов. Память не освобождается. Это происходит только при вызове clear.
7 коммент.:
For doing this portably, you need to write your own allocator. :-(
Я бы использовал тут слово "стандартно" вместо "правильно", потому как правильно было б не освобождать память. Освобождение исключает возможность повторного использования уже выделенной памяти
size() и capacity() - не есть одно и то же. Память изначально выделяется с некоторым запасом, чтобы при добавлении элементов в вектор не было постоянной переаллокации (ибо это тормоза, чем дальше - тем больше). Так что, capacity() говорит о размере пула памяти, выделеной данному вектору, а вот size() - это кол-во элементов, которые реально используются из этого пула.
Когда capacity() == size(), вставка очередного элемента вызовет
1) аллокацию нового пула (скорее всего, вдвое большего, чем раньше)
2) копирование содержимого старого пула в новый
3) освобождение старого пула
Если Вам не нравится такое поведение - смотрите на другие контейнеры, например, лист (двусвязный список).
2Анонимный:
size() и capacity() - не есть одно и то же.
1) аллокацию нового пула (скорее всего, вдвое большего, чем раньше)
Если Вам не нравится такое поведение
Речь идет об освобождении памяти, выделенной под вектор, а не о выборе контейнеров.
Уменьшение размеров вектора не уменьшает его его емкости. Чтобы вернуть память системе, нужно сделать следующий трюк:
vector tmp = v;
v.swap(tmp);
Ни .clear(), ни reserve(x) у меня память не освобождают.
Освободить память удаётся только так: std::vector().swap(vec);
Просит удаления неиспользуемых мощностей.
Это необязательный просьбой сократить capacity в size. Это зависит от реализации, если запрос выполняется.
void shrink_to_fit(); // (начиная с C++11)
Пример:
std::vector v;
v.clear(); // очищает содержимое вектора .
v.shrink_to_fit(); // сокращает зарезервированный размер памяти вектора .
Deleaker ищет утечки ресурсов в программах на С++: утечки памяти, дескрипторов, GDI объектов и многие другие.Работает как расширение в Visual Studio, так и в виде отдельного приложения.
4 ответа 4
не имеет смысла. OrderVector - это имя типа. Поэтому применять к нему оператор индексирования бессмысленно.
Все можно сделать без всякого написания вручную цикла с помощью стандартного алгоритма std::for_each и стандартного функционального объекта std::default_delete .
Вот демонстрационная программа.
Ее вывод на консоль
Если хотите использовать цикл вместо алгоритма, то достаточно написать
Результат будет такой же, что и для программы, показанной выше.
Что касается вашего собственного цикла, то правильно его будет записать следующим образом:
Обратите внимание, что вместо данного объявления конструктора
будет лучше записать
Также в виду того, что вы используете вектор указателей, вам следует либо запретить копирование объектов класса, как, например, в определении класса записать
Либо определить их явно.
Company.h: In destructor ‘virtual Company::~Company()’: Company.h:26:13: error: ‘default_delete’ is not a member of ‘std’ std::default_delete
@AntonBarinov Вы должны включить заголовок
Если вы хотите чтобы при удалении элементов автоматически выполнялся их деструктор, то вам нужно либо завернуть указатели в "умные указатели", либо хранить в векторе не указатели, а сами объекты.
Для первого варианта можно (и нужно!) использовать std::shared_ptr . Однако в этом случае деструктор Order будет вызываться не обязательно когда удаляется вектор. Он будет вызываться когда удалится последний умный указатель на его объект:
Второй вариант, деструктор вектора автоматически вызовет деструкторы для каждого элемента:
Что такое delete OrderVector[*it]; .
Вам нужно просто в цикле сделать
Однако имейте в виду, что если с вектором такой номер еще пройдет, то вот с другим типом контейнера запросто могут возникнуть проблемы.
Контейнеры с более сложной структурой ( set , unordered_map и т.п.) могут требовать того, чтобы все элементы контейнера содержали корректные значения во все моменты времени. Разрушать содержимое элемента контейнера в них можно только вместе с удалением (и только после удаления) самого элемента из контейнера.
В том числе именно по этой причине имеет смысл использовать "умные указатели" для хранения указателей в контейнерах.
Или это лишние?
Или же очищать то и ничего не надо (для избежания мемори ликсов), т.к. в векторах у меня wchar_t ?
2. Как очистить с релоакацией памяти вектор вектором моего типа? Ну чтоб память ими занимаемая была равна нулю?
Определить для заданных векторов длину каждого вектора и найти номер самого длинного вектора
Создайте структуру Вектор с элементами x, y, z – декартовые координаты. Определить для M заданных.
Корректное удаление двумерного динамического массива
Доброго времени суток. В программе имеется двумерный динамический массив. Особенность его в том.
Использование вектора векторов
Здравствуйте, у меня возник вопрос, который я не могу понять, как решить. Проблема заключается в.
Использование вектора векторов
Нужно хранить символы в координатах, например, на пятой строчке, третьей позиции хранится символ.
Как очистить с релоакацией памяти вектор вектором моего типа? Ну чтоб память ими занимаемая была равна нулю?
Тайпдеф здесь для красоты.
А вообще можете не переживать за память внутренних векторов. Она почистится вызовами деструкторов при вызове data.clear(). Но ели вы все же хотите подсократить память то либо вариант выше либо вызывать метод shrink_to_fit для каждого внутреннего вектора если они не пусты.
SuperHero, у вектора есть деструктор, он память освободит корректно.
Сперва создается временный безымянный вектор. Затем его внутренние указатели на блок динамической памяти перебрасываются с другим вектором при вызове swap. Далее так как теперь безымянный объект владеет всеми данными то при выходе из локальной области видимости он будет разрушен вместе со всеми данными и на выходе вы получаете пустой исходный вектор.
Читайте также: