Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Либерти Джесс. Освой самостоятельно С++ за 21 день. - royallib.ru.rtf
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
2.55 Mб
Скачать

Что такое утечка памяти

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

1: unsigned short int * pPointer = new unsigned short int;

2: *pPointer = 72;

3: delete pPointer;

4: pPointer = new unsigned short int;

5: *pPointer = 84;

В строке 1 объявляется указатель и выделяется память для хранения переменной типа unsigned short int. В следующей строке в выделенную область записывается значение 72. Затем в строке 3 указателю присваивается адрес другой области памяти, в которую записывается число 84 (строка 4). После выполнения таких операций память, содержащая значение 72, оказывается недоступной, поскольку указателю на эту область было присвоено новое значение. В результате невозможно ни использовать, ни освободить зарезервированную память до завершения программы. Правильнее было бы написать следующее:

1: unsigned short int * pPointer = new unsigned short int;

2: *pPointer = 72;

3: pPointer = new unsigned short int;

4: *pPointer = 84;

В этом случае память, выделенная под переменную, корректно освобождается (строка 3).

Примечание: Каждый раз, когда в программе используется оператор new, за ним должен следовать оператор delete. Очень важно следить, какой указатель ссылается на выделенную область динамической памяти, и вовремя освобождать ее.

Размещение объектов в области динамической памяти

Аналогично созданию указателя на целочисленный тип, можно динамически размещать в памяти любые объекты. Например, если вы объявили объект класса Cat, для манипулирования этим объектом можно создать указатель, в котором будет храниться его адрес, — ситуация, абсолютно аналогичная размещению переменных в стеке. Синтаксис этой операции такой же, как и для целочисленных типов:

Cat *pCat = new Cat;

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

Удаление объектов

При использовании оператора delete, за которым следует идентификатор указателя на объект, вызывается деструктор соответствующего класса. Это происходит еще до освобождения памяти и возвращения ее в область динамического обмена. В деструкторе, как правило, освобождается вся память, занимаемая объектом класса. Пример динамического размещения и удаления объектов показан в листинге 8.5.

Листинг 8.5. Размещение и удаление объектов в области динамического обмена

1: // Листинг 8.5.

2: // Размещение и удаление объектов в области динамического обмена

3:

4: #include <iostream.h>

5:

6: class SimpleCat

7: {

8: public:

9:    SimpleCat();

10:   ~SimpleCat();

11: private:

12:   int itsAge;

13: };

14:

15: SimpleCat::SimpleCat()

16: {

17:    cout << "Constructor called.\n";

18:    itsAge = 1;

19: }

20:

21: SimpleCat::~SimpleCat()

22: {

23:    cout << "Destructor called.\n";

24: }

25:

26: int main()

27: {

28:    cout << "SimpleCat Frisky...\n";

29:    SimpleCat Frisky;

30:    cout << "SimpleCat *pRags = new SimpleCat...\n";

31:    SimpleCat * pRags = new SimpleCat;

32:    cout << "delete pRags...\n";

33:    delete pRags;

34:    cout << "Exiting, watch Frisky go...\n";

35:    return 0;

36: }

Результат:

SimpleCat Frisky...

Constructor called.

SimpleCat *pRags = new SimpleCat..

Constructor called.

delete pRags...

Destructor called.

Exiting, watch Frisky go...

Destructor called.

Анализ: В строках 6—13 приведено описанИе простейшего класса SimpleCat. Описание конструктора класса находится в строке 9, а его тело — в строках 15-19. Деструктор описан в строке 10, его тело — в строках 21-24.

В строке 29 создается экземпляр описанного класса, который размешается в стеке. При этом происходит неявный вызов конструктора класса SimpleCat. Второй объект класса создается в строке 31. Для его хранения динамически выделяется память и адрес записывается в указатель pRags. В этом случае также вызывается конструктор. Деструктор класса SimpleCat вызывается в строке 33 как результат применения оператора delete к указателю pRags. При выходе из функции переменная Frisky оказывается за пределами области видимости и для нее также вызывается деструктор.