{lang: ‘ru’}

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

В строке

int arr [ 100 ];

зарезервировано память для 100 элементов типа int. Массивы являются разумным подходом к хранению данных, однако имеют серьезный недостаток: при написании программы необходимо знать, насколько большой массив нам необходим. Следующий подход не сработает:

cin >> size; // получение желаемого размера
int аrr [size]; // ошибка, ведь раз мер массива должен быть константой!

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

Операция new

В С++ предлагается другой подход к выделению памяти: операция new. Это - универсальная операция, которая получает память у операционной системы и возвращает указатель на начало выделенного блока. В следующей программе продемонстрировано, как это работает:

#include
#include
using namespace std;
int main ( )
{
    char* str = "Очень длинная строка.";
    int len = strlen ( str ); // вычисление длины строки
    char* ptr; // определим переменную
    ptr = new char [ len +1 ]; // выделяем память, используя оператор new
    strcpy ( ptr, str ); // копируем str у ptr
    cout<< "ptr = " << ptr << endl; // содержание ptr
    delete [] ptr; // освобождение выделенной памяти, оператор delete
    return 0;
}

Выражение

ptr = new char [ len + 1 ];

присваивает переменной ptr значение адреса блока памяти, достаточного для сохранения строке str, длину которого можно получить, используя библиотечную функцию
strlen(), добавив дополнительный байт для символа окончания строки.
Результат работы программы:

ptr = Очень длинная строка.

Операция delete

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

delete [] ptr;

возвращает системе память, на которую указывал указатель ptr.

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

ptr = new SomeClass; // создание одинарного объекта, оператор new
delete ptr; // скобки не нужны, оператор delete

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

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

class F
{
private:
    int data;
public:
    Foo():data(0)
    { }
    ~Foo()
    { }
};

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

#include
#include //для strcpy()
using namespace std;
////////////////////////////////////////////////////////////////
class String
{
private:
    char* str; // указатель на строку
public:
    String(char* s) //конструктор с одним аргументом
    {
        int length = strlen(s); //длина строки
        str = new char[length+1]; //выделение необходимой памяти, оператор new
        strcpy(str, s); //копирование строки
    }
    ~String() //деструктор
    {
        cout << "Уничтожение строкиn";
        delete[] str; //освобождение памяти, оператор delete
    }
    void display() //вывести строку
    {
        cout << str << endl;
    }
};
////////////////////////////////////////////////////////////////
int main()
{
    String s1 = "Очень длинная строка.";
    cout << "s1=";
    s1.display();
    return 0;
}

Результат:

s1 = Очень длинная строка.
Уничтожение строки

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

с реальными соперниками. Игры на любой вкус. Такого разнообразия вы еще не видели.


Получайте новые статьи блога прямо себе на почту