Стек и куча
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 12 из 104.
Программы на C++ используют две основные области памяти: стек и кучу. Понимание того, где находятся ваши объекты, имеет решающее значение для написания эффективного кода без ошибок.
Стек — это быстрая автоматическая память. Переменные, объявленные внутри функций, живут здесь и автоматически уничтожаются, когда они выходят из области видимости.
void example() {
int x = 10; // Выделение в стеке
Player player; // Выделение в стеке — уничтожается автоматически
} // x и player уничтожаются здесьКуча — это более объемная, но более медленная память, которой вы управляете вручную. Объекты в куче сохраняются до тех пор, пока вы явно их не удалите.
void example() {
Player* player = new Player(); // Выделение в куче
// player существует до тех пор, пока не будет удален
delete player; // Требуется ручная очистка
}Ключевые различия:
| Стек | Куча |
|---|---|
| Быстрое выделение памяти | Более медленное выделение памяти |
| Ограниченный размер | Большая емкость |
| Автоматическая очистка | Требуется ручная очистка |
| Объекты фиксированного размера | Объекты динамического размера |
Используйте выделение памяти в стеке для небольших, кратковременных объектов. Используйте выделение памяти в куче, когда объекты должны существовать дольше своей области видимости или когда их размер определяется во время выполнения.
Забывание об освобождении памяти в куче приводит к утечкам памяти, распространенному источнику ошибок в программах на C++.
Задание
ЛегкоДавайте изучим разницу между стековой и кучевой памятью, создав простой класс Counter, который отслеживает, как создаются и уничтожаются объекты.
Вы создадите два файла для организации вашего кода:
Counter.h: Определите классCounterс приватным атрибутомname(string). Включите конструктор, который принимает имя и выводит"Creating: <name>", и деструктор, который выводит"Destroying: <name>". Добавьте методgetName()для возврата имени счетчика.main.cpp: Продемонстрируйте распределение памяти как в стеке, так и в куче. Прочитайте имя из входных данных, затем:- Создайте объект
Counterв стеке, используя это имя - Создайте объект
Counterв куче с именем"HeapCounter" - Выведите имена обоих счетчиков в формате
"Stack: <name>"и"Heap: <name>" - Удалите объект, созданный в куче, чтобы предотвратить утечку памяти
- Создайте объект
Обратите внимание, как сообщения конструктора и деструктора появляются в разном порядке в зависимости от того, когда вы создаете и удаляете каждый объект. Объект в стеке будет автоматически уничтожен по завершении main(), в то время как объект в куче должен быть удален явно.
Подключите ваш заголовочный файл в main.cpp с помощью #include "Counter.h".
Шпаргалка
Программы на C++ используют две основные области памяти: стек и кучу.
Стек — это быстрая автоматическая память. Переменные, объявленные внутри функций, живут здесь и автоматически уничтожаются при выходе из области видимости:
void example() {
int x = 10; // Выделение в стеке
Player player; // Выделение в стеке — уничтожается автоматически
} // x и player уничтожаются здесьКуча — это более объемная, но медленная память, которой вы управляете вручную. Объекты в куче сохраняются до тех пор, пока вы явно их не удалите:
void example() {
Player* player = new Player(); // Выделение в куче
// player существует до тех пор, пока не будет удален
delete player; // Требуется ручная очистка
}Ключевые различия:
| Стек | Куча |
|---|---|
| Быстрое выделение | Более медленное выделение |
| Ограниченный размер | Большая емкость |
| Автоматическая очистка | Требуется ручная очистка |
| Объекты фиксированного размера | Объекты динамического размера |
Используйте выделение в стеке для небольших, кратковременных объектов. Используйте выделение в куче, когда объекты должны существовать дольше своей области видимости или когда их размер определяется во время выполнения. Если забыть удалить память в куче, это приведет к утечкам памяти.
Попробуйте сами
#include <iostream>
#include <string>
#include "Counter.h"
using namespace std;
int main() {
// Считать имя из входных данных
string inputName;
cin >> inputName;
// TODO: Создать объект Counter в стеке, используя inputName
// TODO: Создать объект Counter в куче с именем "HeapCounter"
// TODO: Вывести имя счетчика в стеке в формате "Stack: <name>"
// TODO: Вывести имя счетчика в куче в формате "Heap: <name>"
// TODO: Удалить счетчик, выделенный в куче, чтобы предотвратить утечку памяти
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнер