Стек, куча и динамическое распределение памяти - PullRequest
0 голосов
/ 17 декабря 2018

У меня есть некоторая путаница в отношении этих трех понятий: стек, куча и динамическое распределение памяти.Я приведу примеры на C ++.

  1. Правильно ли сказать, что данная программа со всеми ее переменными, массивами и, возможно, объектами в стеке, когда программа только запускается, всенеобходимый объем памяти уже есть, так что все предопределено?Но когда программа запущена, для меня она все еще звучит как «динамическая», так как стек все еще изменяется в том смысле, что значения все еще помещаются в стек во время выполнения.

  2. Что касается кучи, для "динамического" смысла я привел идею из какого-то ответа на этом сайте, она для чего-то определенного во время выполнения:

    cin >> box_size;
    int *box = new int[box_size];
    

    Но, тогда как насчет этого :

    Box surprise_box = new Box();
    

    Я уже знаю, сколько места нужно для компиляции, верно?Но это все еще в куче.Таким образом, кажется, что «Динамическое» выделение памяти - это почти что бремя выделения / освобождения памяти становится одним из задач программиста.

†: вместо этого должно быть Box *ptr_surprise_box = new Box();.(Спасибо за комментарий)


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

Ответы [ 4 ]

0 голосов
/ 17 декабря 2018

Пользователь slava упомянул следующее:

automatic, static, thread и dynamic

Я будусосредоточиться на всех, кроме thread.Он также заявил следующее:

Для C ++ не существует такой вещи, как стек или куча


Пользователь Даже Теран заявил следующее:

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

Вещи, выделенные в стеке, уничтожаются при выходе из области видимости.Вещи, выделенные в куче, будут существовать до тех пор, пока они не будут явно освобождены с помощью команды delete, free или delete [] (в зависимости от того, как они распределены).


Я объединю два предыдущих ответав один ответ с демонстрациями:


  • 1 st - Automatic Storage

int main () {
    int x = 5;

    { // new scope
        int x = 7;
        std::cout << x << '\n';  // prints 7     
    } // end scope

    std::cout << x << '\n';  // prints 5

    return 0;
}

Это считается Automatic Storage, поскольку объявления переменных и память уничтожаются, когда они выходят из области видимости.Вы можете считать это переменной stack в некотором смысле, поскольку в C ++ каждый function имеет stack frame.Эти переменные x выше оба живут в кадре стека main.cpp, но имеют automatic storage.Однако при первом вызове std::cout будет напечатано 7, поскольку оно находится в той же области действия, что и объявленная x переменная 2 и .Как только достигается closing фигурная скобка }, эта область действия уничтожается, равно как и переменная 2 nd x.Поэтому, когда мы дойдем до следующего вызова std::cout, будет напечатано 5, потому что он находится в той же области действия, что и объявленный x 1 st .


  • 2 и - Dynamic Storage

int main() {
   int x = 5;  // Automatic storage
   int* ptr = nullptr; // raw pointer

   ptr = new int(x); // Dynamic Storage
   std::cout << "x = " << x << '\n';        // prints 5
   std::cout << "*ptr = " << *ptr << '\n';  // prints 5

   { // new scope
       *ptr = 12;
   } // end scope

   std::cout << "x = " << x << '\n';        // x unchanged prints 5
   std::cout << "*ptr = " << *ptr << '\n';  // prints 12

   delete ptr; // clean up memory

   return 0;
}

Dynamic Storage живет дольше, чем область, в которой она объявлена. Вы можете передавать динамическую память из одной функции в другую, если исходный объект, на который она ссылается, остается действительным, в противном случае у вас будет утечка памяти, недействительный или зависший указатель, который можетпривести к нежелательному поведению, неопределенному поведению, аварийному завершению программы, удалению вашей ОС и запуску ядерных бомб!(Ну, последнее немного драматично; но не смейтесь, потому что плохое управление памятью приведет к хаосу в вашей кодовой базе, и ВСЕ КТО использует это!).Это позволяет вам хранить данные и изменять их из одной функции в другую, не создавая копии на их копии каждый раз, когда вам нужно ссылаться на них в каком-либо другом вычислении.


  • 3 rd - Static Storage

static int i = 0; // static storage: life time of application or file scope; similar to a global...

void add1() {
   i++;
}

int main() {
    std::cout << i << '\n';
    add1();
    std::cout << i << '\n';

    for ( int n = 0; n < 10; n++ ) {
        add1();
        std::cout << "n=" << n << ": " << i << '\n';
    }

    return 0;
}

Выход

0
1
n=0: 2
n=1: 3
n=2: 4
n=3: 5
n=4: 6
n=5: 7
n=6: 8
n=7: 9
n=8: 10
n=9: 11

Static Storage немного отличается.Нет необходимости очищать его как динамическую память, поскольку он имеет свойства, подобные Automatic Storage, поскольку он будет уничтожен автоматически.Тем не менее, они обычно встречаются в global namespace или global file space, и они могут быть полезны, но глобальные переменные снова могут быть опасными, если не управляются или не используются должным образом.Обычно они имеют время жизни программного приложения, если оно определено в main.cpp, или время жизни области видимости файла, если оно определено в каком-то другом файле cpp.Единственное другое отличие от Static Storage в том, что он также инициализируется только один раз, и обычно есть только один его экземпляр!


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

0 голосов
/ 17 декабря 2018
  1. Вообще-то да.В начале вашей программы большая часть данных находится в стеке, когда вы вызываете функцию, тогда вы можете выделить память в куче.(Ну, в программе есть не только stack или heap, но и в других сегментах могут быть глобальные переменные, это длинная история).

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

Пространство кучи выделяется вами, когда вам нужно немного памяти, вы вызываете функцию для выделения пространства кучи длявы.

Указатель на адрес памяти является переменной в стеке

Для вашего кода:

cin >> box_size;
int *box = new int[box_size];

Здесь box - это переменная в стеке.Значение переменной box является указателем на память в куче.

Но Box surprise_box = new Box(); не является допустимым синтаксисом.

Примеры:

  • Box box1;: переменная box1 находится в стеке.

  • Box *box2 = new Box();:переменная box2 находится в стеке, это указатель, указывает на память new Box()

Обновлено:

Нет четкого "динамического" определенияс концепцией «куча» и «стек».Например, в C99, если вы делаете scanf("%d", &size); int a[size];все еще в порядке, и a может быть в стеке, а не в куче.Все зависит от поведения компилятора.Выделенная вами память обычно находится в куче (вы называли функции выделения памяти, включая new()), память, выделенная кодом компилятора, обычно находится в стеке.

ps: Я думаю, что ответ @ Славы довольно хороший.Эти conepts находятся в разных областях.stack и heap в основном связаны с ОС, dynamic и static в основном связаны с языком.Я только что говорил о большинстве реализаций современного языка C ++, они поместили new() памяти в кучу и т. Д.

0 голосов
/ 17 декабря 2018

У меня есть некоторая путаница в отношении этих трех понятий: стек, куча и динамическое распределение памяти.

Конечно, вы смешали понятия из разных областей - первые 2 относятся к ОС, а затем к языку.

Для C ++ не существует такой вещи, как стек иликуча.Существует 4 различных срока хранения объектов в C ++: автоматический, статический, потоковый и динамический .Да, объекты с автоматическим хранением обычно хранятся в стеке, а объекты с динамическим - в куче, но это детали реализации - с языковой точки зрения таких вещей нет.Подробности о сроке хранения можно найти здесь

0 голосов
/ 17 декабря 2018

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

Вещи, выделенные в стеке, уничтожаются при выходе из области видимости.Вещи, выделенные в куче, будут существовать до тех пор, пока они не будут явно освобождены с помощью delete, free или delete[] (в зависимости от того, как они распределены).

Чтобы ответить на ваши вопросы:

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

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

Таким образом, похоже, что «Динамическое» выделение памяти - это почти что бремя выделения / освобождения памяти становится одним из задач программиста.

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

...