Различия между динамической памятью и «обычной» памятью

Каковы некоторые из технических различий между памятью, которая выделяется сnew оператор и память, которая выделяется с помощью простого объявления переменных, таких какint var? Есть ли в C ++ автоматическое управление памятью?

В частности, у меня есть пара вопросов. Во-первых, поскольку с динамической памятью необходимо объявить указатель для хранения адреса фактической памяти, с которой вы работаете, динамическая память не используется.more объем памяти? Я не понимаю, зачем нужен указатель, если только вы не объявляете массив.

Во-вторых, если бы я сделал простую функцию, такую как эта:

int myfunc() { int x = 2; int y = 3; return x+y; }

... И назовите это, освободится ли память, выделенная функцией, как только закончится область ее существования? Как насчет динамической памяти?

 Treb20 июн. 2009 г., 16:22
@ Johannes: Если вы используете 64-битную ОС, я предполагаю, что у вас достаточно памяти, чтобы 8 байтов тоже не имели большого значения ;-)
 Joey20 июн. 2009 г., 16:53
Ну, ни 4, ни 8 байтов не имеют большого значения. Одиночный указатель - это то, что мне безразлично. Несколько миллионов из них ... ну, тогда это становится интересным :-). Но указатель не обязательно всегда 4 байта, это все, что я хотел сказать :-)
 marcc20 июн. 2009 г., 09:27
Я думаю, что вы ищете термины стек и куча. Когда вы используетеnew или жеmalloc() Вы выделяете память из кучи. Когда вы выделяете объект внутри функции (как вint x = 2), он идет в стек.
 Treb20 июн. 2009 г., 09:40
Ваше предположение, что создание объекта с "новым" требуется больше памяти, потому что указатель, необходимый для доступа к объекту, является правильным. Однако, поскольку динамическое управление памятью служит иным целям, нежели статический MM, сравнение не имеет смысла. И, эй, всего 4 байта! ;-)

Ответы на вопрос(5)

Память, выделенная в функции, находится внутри функции, в которой функция размещена в стеке.

Читайте о стеке и распределении кучи здесь:http://www-ee.eng.hawaii.edu/~tep/EE160/Book/chap14/subsection2.1.1.8.html

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

Что касается вашего вопроса об использовании памяти в функции, в вашем примере память для ваших локальных переменных будет освобождена в конце функции. Однако, если память была динамически распределена сnew, он не будет автоматически удален, и вы будете нести ответственность за явное использованиеdelete освободить память.

Что касается автоматического управления памятью, стандартная библиотека C ++ предоставляет для этого auto_ptr.

выделенная новым оператором, извлекается из секции памяти, называемой «куча» в то время как статические распределения для переменных используют раздел памяти, совместно используемый с вызовами процедур / функций («стек»).

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

The big difference between "dynamic" and "ordinary" memory was rather good reflected in the question itself.

Динамическая память не слишком хорошо поддерживается C ++.

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

Вам нужен дополнительный указатель, поскольку каким-то образом вам нужен доступ к вашей новой памяти. Некоторая память (динамическая или нет) - это прежде всего то, с чем не может справиться язык программирования. Вы должны иметь доступ к нему. Это делается с помощью переменных. Но переменные в таких языках, как C ++, хранятся в «обычном» формате. объем памяти. Таким образом, вам нужно иметь «указатели» - указатели являются формой косвенного обращения, которая говорит: «Нет, я не та ценность, которую вы ищете, но я указываю на нее». Указатели являются единственной возможностью в C ++ для доступа к динамической памяти.

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

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

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

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

Решение Вопроса

Note: Этот ответway слишком долго. Я срежу это когда-нибудь. Тем временем, прокомментируйте, если можете придумать полезные правки.

Чтобы ответить на ваши вопросы, нам сначала нужно определить две области памяти, называемыеstack иheap.

The stack

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

A simple example
int main(int argc, char * argv[])
{
    int a = 3;
    int b = 4;
    return a + b;
}

В этом случае у вас есть одна коробка на полу с переменнымиargc (целое число),argv (указатель на массив символов),a (целое число) иb (целое число).

More than one box
int main(int argc, char * argv[])
{
    int a = 3;
    int b = 4;
    return do_stuff(a, b);
}

int do_stuff(int a, int b)
{
    int c = a + b;
    c++;
    return c;
}

Теперь у вас есть коробка на полу (дляmain) сargc, argv, a, а такжеb, Поверх этой коробки у вас есть другая коробка (дляdo_stuff) сa, b, а такжеc.

Этот пример иллюстрирует два интересных эффекта.

As you probably know, a and b were passed-by-value. That's why there is a copy of those variables in the box for do_stuff.

Notice that you don't have to free or delete or anything for these variables. When your function returns, the box for that function is destroyed.

Box overflow
    int main(int argc, char * argv[])
    {
        int a = 3;
        int b = 4;
        return do_stuff(a, b);
    }

    int do_stuff(int a, int b)
    {
        return do_stuff(a, b);
    }

Здесь у вас есть коробка на полу (дляmain, как прежде). Тогда у вас есть ящик (дляdo_stuff) сa а такжеb, Затем у вас есть еще одна коробка (дляdo_stuff называя себя), снова сa а такжеb, А потом еще. И скоро у вас есть стекoverflow.

Summary of the stack

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

More technical stuff Each "box" is officially called a stack frame. Ever notice how your variables have "random" default values? When an old stack frame is "destroyed", it just stops being relevant. It doesn't get zeroed out or anything like that. The next time a stack frame uses that section of memory, you see bits of old stack frame in your local variables. The heap

Это где динамическое распределение памяти вступает в игру.

Представьте себе кучу бесконечного зеленого луга памяти. Когда вы звонитеmalloc или жеnewблок памяти выделяется в куче. Вам дан указатель для доступа к этому блоку памяти.

int main(int argc, char * argv[])
{
    int * a = new int;
    return *a;
}

Здесь новое целое число памяти выделяется в куче. Вы получаете указатель с именемa это указывает на эту память.

a is a local variable, and so it is in main's "box" Rationale for dynamic memory allocation

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

Returning an array
int main(int argc, char * argv[])
{
    int * intarray = create_array();
    return intarray[0];
}

int * create_array()
{
    int intarray[5];
    intarray[0] = 0;
    return intarray;
}

Что здесь происходит? Вы "возвращаете массив" вcreate_array, В действительности вы возвращаете указатель, который просто указывает на частьcreate_array & Quot; коробка & Quot; который содержит массив. Что происходит, когдаcreate_array возвращается? Его коробка уничтожена, и вы можете ожидать, что ваш массив станет поврежденным в любой момент.

Вместо этого используйте динамически распределенную память.

int main(int argc, char * argv[])
{
    int * intarray = create_array();
    int return_value = intarray[0];
    delete[] intarray;
    return return_value;
}

int * create_array()
{
    int * intarray = new int[5];
    intarray[0] = 0;
    return intarray;
}

Поскольку функция возврата не изменяет кучу, ваш драгоценныйintarray убегает невредимым. Запомниdelete[] это после того, как вы все сделали.

Ваш ответ на вопрос