Указатели и динамическая память в C++

Что такое указатель, чем отличается от ссылки, как работают new и delete, откуда берутся утечки памяти и почему на защите спрашивают про деструктор.

Указатель — это переменная, которая хранит не значение, а адрес другой переменной в памяти. Всё остальное в теме указателей — следствие этого одного факта.

int x = 42;
int* p = &x;   // p хранит адрес x
std::cout << *p;  // 42 — разыменование: "значение по адресу"
*p = 100;         // меняем x через указатель
std::cout << x;   // 100

Указатель, ссылка и массив

Стек и куча

Локальные переменные живут на стеке и умирают при выходе из функции — размер должен быть известен на этапе компиляции. Если размер известен только во время выполнения (например, пользователь ввёл n), память берут в куче через new и обязаны вернуть через delete.

int n;
std::cin >> n;
int* arr = new int[n];   // выделили
// ... работа с массивом ...
delete[] arr;            // освободили; для new — delete, для new[] — delete[]
arr = nullptr;           // хорошая привычка
Каждому new должен соответствовать ровно один delete. Забыли — утечка памяти. Вызвали дважды — падение программы (double free).

Правило трёх и почему про него спрашивают

Если класс владеет динамической памятью, компилятор по умолчанию копирует только сам указатель. Два объекта начинают ссылаться на одну область памяти, и при разрушении второго происходит повторное удаление. Поэтому такому классу нужны деструктор, конструктор копирования и оператор присваивания — это и есть «правило трёх».

class Vec {
    int* data; size_t n;
public:
    Vec(size_t n) : data(new int[n]), n(n) {}
    Vec(const Vec& o) : data(new int[o.n]), n(o.n) {          // копирование
        std::copy(o.data, o.data + o.n, data);
    }
    Vec& operator=(const Vec& o) {                            // присваивание
        if (this == &o) return *this;
        delete[] data;
        n = o.n; data = new int[n];
        std::copy(o.data, o.data + n, data);
        return *this;
    }
    ~Vec() { delete[] data; }                                 // деструктор
};

Современный подход: умные указатели

Ошибки, за которые снижают оценку

ОшибкаЧто происходит
Возврат адреса локальной переменнойВисячий указатель: память уже освобождена, поведение непредсказуемо
delete вместо delete[]Деструкторы остальных элементов не вызываются, поведение не определено
Отсутствие проверки на nullptrПадение при разыменовании
Выход за границы массиваПорча чужой памяти, ошибка проявляется в другом месте программы

Частые вопросы

Чем указатель отличается от ссылки?

Указатель — самостоятельная переменная с адресом, её можно переназначить и обнулить. Ссылка — это второе имя существующего объекта, она не может быть «пустой» и не переназначается.

Зачем нужен виртуальный деструктор?

Если удалять объект наследника через указатель на базовый класс, без virtual вызовется только деструктор базы — память наследника утечёт.

Читайте также

Сделаем работу по этой теме

Опишите задачу — ответим в течение 15 минут в личных сообщениях ВКонтакте, назовём срок и цену. Предоплаты за оценку нет.

  • Оценка заявки бесплатно
  • Правки по замечаниям преподавателя
  • Работы по всем техническим и IT-дисциплинам

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