Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > динамическая память и массивы |
Автор: bern 2.12.2005, 23:54 |
Здраствуйте! У меня к вам такая просьба - объясните мне пожалуйста чем таким кардинальным отличается динамическая память от массивов и что можно сделать с помощью new&delete чего нельзя было бы сделать с помощью массивов? Ведь в динамической памяти точно также выделяется место под отдельные переменные и массивы, так в чём разница ? И вообще почему этот метод называется динамическим? |
Автор: blackofe 3.12.2005, 00:26 | ||
в c++ массивы должны иметь константную размерность. динамическое выделение памяти позволяет объявить массив произвольного размера (который, вообще говоря, не известен на этапе компиляции). |
Автор: Dray 3.12.2005, 00:32 | ||||||||||
Если делаешь так:
То а создается в стеке. Если так:
То а создается в куче. Разница в том, что переполнение стека куда реальнее чем переполнение кучи. Вообще указатели и динамическое распределение памяти чаще используются для структур данных самодельных например в списках:
Если интересно про списки то лучше воспользоваться поиском. Это уже обсуждалось. Динамической она называется поскольку количество требуемой памяти определяется во время выполнения программы. Например при создании масива так:
Нужно заранее знать кол-во элементов массива. И использовать только константу. А если так:
Не обязательно знать колличество элементов заранее можно ввести прям с клавиатуры. Память распределяется динамически. |
Автор: Aleksandor 3.12.2005, 00:32 |
Динамический способ рулит потому что- а) экономит память (и за счет этого повышает быстродействие программы). Часто это вообще критично для программы. б) не загромождает стек - массив (статический) как любая другая переменная передается в стеке и если он велик то произойдет переполнение стека отведенного потоку и приложение рухнет ![]() часто мы не знаем сколько элементов будет в массиве и соответственно сколько памяти потребуется, поэтому лучше выделять память динамически, по мере роста массива. new только один из способов, в Win API используем HeapAlloc и VirtualAlloc Пример недостатки статического выделения памяти- char array[1000][1000]; // массив 1000 строк по 1000 байт каждая - если массив не в глобальной памяти, то он вызовет переполнение стека - каждая строка может содержать всего 1 символ (+нулевой байт), итого 2 байта. остальные 998000 байт расходуются впустую - длина строки может превысить 1000 байт, тогда мы не сможем впихнуть ее в массив - мы можем не знать заранее сколько строк потребуется, может всего одна, а может 1001, в первом случае мы зря расходуем до 999998 байт, во втором вообще труба. Нельзя всунуть больше 1000 строк в этот массив! Динамическое выделение памяти снимает все эти проблемы ![]() |
Автор: maxim1000 3.12.2005, 16:02 |
ну и контроль времени жизни еще можно упомянуть с точки зрения памяти время жизни - время, когда объект занимает память в случае использования стека время жизни контролируется тем, когда выполнение входит в блок, в котором объявлен объект, и тем, когда выходит в случае с динамическим распределением можно удалять объект раньше или позже в зависимости от, например, булевой переменной... |
Автор: Guest 3.12.2005, 19:23 |
Спасибо за отеты.Можно ещё один вопрос , хоть и не в тему , но создавать новый топик не хочется.Есть вот такой код: [code=cpp] #include <iostream.h> #include <string.h> class Person { public: Person(char *pN) { cout << "Sozdayom " << pN << "\n"; pName = new char[strlen(pN) + 1]; if (pName != 0) { strcpy(pName, pN) ; } } ~Person() { cout << "Likvidiruem " << pName << "\n"; pName[0] = '0'; cout << pName << "\n"; delete pName; cout << pName << "\n"; } char *pName; }; void fn() { Person p1 ("Stroka"); Person p2 = p1; } int main(int argcs, char* pArgs[]) { fn(); int d; cin >> d; return 0; } [code=cpp] Вопрос в следующем каким образом указатель pName превратился в массив pName[0] и почему в этом массиве можно присвоить значение только первому элементу , т.е. pName[1] = '0' не работает? |
Автор: nikitao 3.12.2005, 20:24 | ||||||
Guest ,у тебя неправельно написано прога.Нельзя так приравнивать обьекты собственного класса в которых используется динамика(Person).Для этого надо перегрузить оператор '='.Дело в том что когда ты приравниваешь(без перегрузки) два обьекта произходит побитовое копирование одного обьекта в другой т е произходит копирование указателя,но не строки ![]() ![]() ![]() ![]() Ошибка возникает в том что в конце ф-ции fn() вызывается 2 деструктора(для p1 и p2),но когда срабатывает деструктор для p2 строка уже удалена деструктором p1(указатели же указывают на один участок).Так что надо доработать. Надо писать не
а
Поскольку это массив
Этого я не понял,все работает если написать pName[1]. ![]() |
Автор: Guest 3.12.2005, 21:57 | ||||
nikitao , да не , я в курсе , просто это немного переделанный пример из книги. Правильно будет вот так :
Как ни странно у меня тоже заработало. |
Автор: Helicopterr 3.12.2005, 22:11 |
Вопрос в тему. Можно ли выделить память опером new для глобального массива? И если да, то где юзать delete[]... |
Автор: nikitao 3.12.2005, 22:14 | ||||||
Все равно не верно(но тут уже мелочи: 1.Почему то во 2 конструкторе нужная длина массива высчитывется првельно а в 1-нет(единицу не прибавили) 2.То что перегружен конструктор не перегружает оператор '='.Соответственно вместо
должно быть
3.Ты так и не исправил ошибку с delete(это про '[]') Добавлено @ 22:18 Helicopterr,да можно,а юзать delete можно где хочешь(можно даже вообще не юзать,но тогда утечка произойдет).Если тебе надо чтоб в самом конце удалялось,то перед
надо писать.И вообще перед каждым return 0 и exit() в ф-ции main это надо будет прописать. |
Автор: S.A.P. 4.12.2005, 01:09 | ||||||||||
аналогичны. Добавлено @ 01:12
delete[] юзается где угодно. Добавлено @ 01:16
как раз тут и не обязательно. Ось сама грохнет всю кучу по завершении программы. Исключение может составлять вызовы деструкторов у объектов в куче, которые должны выполнить какие - то завершающие действия. |
Автор: maxim1000 4.12.2005, 04:31 | ||||
для нормального вызова деструкторов можно сделать так: делаем глобальный объект, у него одно поле - указатель в конструкторе выделяем, в деструкторе освобождаем... |
Автор: oberonchik 4.12.2005, 10:31 |
Я немного вернусь к первому обсуждаемому вопросу в этот посте. У стека есть ещё одна очень неприятная особенность. Он может медленно расти. Например, был опыт под Linux когда стек рос очень медленно после появления потребности. Т.е. создаются обекты в стеке, а система его наращивает лишь когда появляюся конкретные обращения, причем делает это чуть ли не по 4кб. Проблема была серьёзная, производительность была низкая, а задача была критична к этому. Под другими никсами и виндой всё было ок. А под целевой системой Linux никак. Долго я этот баг ловил. Потом выделил динмически и всё начало летать |
Автор: Helicopterr 4.12.2005, 22:39 |
однако я читал что поток в стеке быстрее и для небольших массивов, я думаю, в аллокации смысла нет |
Автор: maxim1000 4.12.2005, 22:54 |
обычно (не буду утверждать, что всегда) стек работает быстрее динамической памяти: т.к. он накладывает свои ограничения на порядок создания/удаления объектов - последний созданный удаляется первым динамическая память не заставляет программиста удовлетворять этому требованию, что приводит у увеличению гибкости и к замедлению выделения/освобождения памяти (из-за различных алгоритмов, связанных с учетом свободного места, которое теперь может быть фрагментированно) сильно подозреваю, что если при использовании динамической памяти все-таки придерживаться политики стека (последний создан - первый удален), эффективность возрастет (правда, динамической памятью часто пользуются именно для того, чтобы создавать и удалять объекты, когда вздумается) но даже тогда на большинстве систем стек, скорее всего, будет быстрее, т.к. он также используется при вызове/возврате из функций, а значит, у него больше шансов оказаться в кеше процессора... |
Автор: Sellini 20.4.2006, 00:46 |
Люди помогите,пожалуйста, надо создать 3-х мерный массив в динамической памяти. |
Автор: MAKCim 20.4.2006, 07:35 | ||||||
1
2.
|
Автор: threef 20.4.2006, 07:53 |
По поводу стека: под виндой он тоже выделяется динамически, по мере использования и тоже постранично, по 4 kb. Можно задавать размеры стека для программ, в которых он является главным хранилищем памяти, например, интенсивно использующим рекурсию. При переполнении стека можно поймать исключение и добавить стек, таким образом проблема переполнения стека снимается, как детская болезнь. Насчет скорости работы в сравнении с кучей - попробую, потом скажу |
Автор: Sellini 21.4.2006, 00:19 |
Спасибо тебе большое, MAKCim, просто выручил, а то зачет неполучить! |
Автор: Sellini 21.4.2006, 00:37 |
... int*** _3d_array=new int** [10]; for (iint i=0; i<10; i++) { *(_3d_array+i)=new int* [10]; for (int j=0; j<10; j++) *(*(_3d_array+i)+j)=new int [10]; } ... А как в этом случае к массиву обращаться? |
Автор: threef 21.4.2006, 14:58 |
_3d_array[1][3][2]= (int)"hello"; |
Автор: Sellini 22.4.2006, 00:19 |
Ага, понял, спасибо. |