Час зберігання об'єкту

Для того, щоб мати можливість оперувати даними у програмі, ми оголошуємо змінні та створюємо об'єкти. Дані, які містять змінні та об'єкти, знаходяться у пам'яті. Для спрощення та відповідності зі стандартом мови, називатимемо і змінні простих вбудованих типів і екземпляри класів просто об'єктами (object).

Коли ми створюємо об'єкт у програмі - ми вказуємо, що необхідно виділити пам'ять для збереження даних, які містить цей об'єкт. У деякий момент, ця пам'ять буде вивільнена (наприклад, якщо програма завершила виконання). Час протягом якого, ці данні будуть доступні, поки пам'ять яка їх містить не буде вивільнена для інших потреб, ми називатимемо часом життя об'єкту (object lifetime).

Час життя пов'язаний з тривалістю зберігання (storage duration) об'єкту. Ми познайомимося з двома видами часу зберігання: автоматичний та статичний.

Автоматичний час зберігання

Звичайні локальні об'єкти, які ми оголошуємо всередині деякого блоку коду, існують лише в межах цього блоку. Тому, коли виконання програми вийде за межі блоку коду, пам'ять автоматично вивільниться.

Покажемо це на прикладі. Для наочної демонстарції, створимо простий клас:

class MyClass
{
public:
    MyClass() { std::cout << "Object created!" << std::endl; }
    ~MyClass() { std::cout << "Object destroyed!" << std::endl; }
};

Цей клас має два спеціальні методи: конструктор MyClass() та деструктор ~MyClass(). Нагалаємо, що для будь якого класу конструктор завжди автоматично викликається, коли створюється новий об'єкт класу. А деструктор, завжди автоматично викликається коли об'єкт класу знищується.

Тепер напишемо дуже просту програму:

int main()
{
    std::cout << "Program begin!" << std::endl;

    {
        MyClass obj;
    }

    std::cout << "Program end!" << std::endl;
}

Тут об'єкт obj створено всередині окремого блоку коду. Після запуску програми ми побачимо вивід у консоль:

Program begin!
Object created!
Object destroyed!
Program end!

Тобто, як тільки виконання блоку коду завершилось - одразу ж викликався деструктор об'єкту і його було видалено з пам'яті.

Автоматичний час зберігання мають також об'єкти оголошені всередині функцій, блоків if, циклів, тощо. Тому ніколи не можна використовувати посилання чи вказівник на автоматичний об'єкт поза межами блоку, в якому він існує. Наприклад, якщо ми маємо функцію яка повертає посилання чи вказівник на локальну змінну всередині функції (чого не можна робити!) і ми скористаємося цим вказівником\посиланням, то у кращому випадку програма аварійно завершиться, а у гіршому - буде працювати некоректно (і як часто буває в таких випадках - дуже дивно).

Ткож варто пам'ятати, що у випадку примітивних типів такіх як int, float, bool, вказівників тощо, автоматичні змінні завжди необхідно ініціалізовувати початковим значенням. Вони не ініціазізуються за замовчуванням автоматично, і якщо їх не ініціалізувати - вони міститимуть довільне значення (по суті, сміття з пам'яті).

void someFunc()
{
    int value1 = 0; // Коректно - ініціалізовано значенням 0
    int value2;     // Не правильно! Необхідно ініціалізувати! Містить "сміття" з пам'яті.
}

Статичний час зберігання

Глобальні об'єкти, а також об'єкти, які оголошені зі специфікатором static існують до завершення роботи програми.

Розглянемо приклад:

MyClass obj;

int main()
{
    std::cout << "Program begin!" << std::endl;
    std::cout << "Program end!" << std::endl;
}

Консольний вивід виглядатиме так:

Object created!
Program begin!
Program end!
Object destroyed!

Як ми бачимо з прикладу, об'єкт оголошений глобально був створений ше до початку виконання main(), а видалений вже після закінчення роботи програми.

У випадку статично змінної (наприклад оголошеної всередині функції):

MyClass obj;

void func()
{
    static MyClass obj;
}

int main()
{
    std::cout << "Program begin!" << std::endl;
    func();
    func();
    std::cout << "Program end!" << std::endl;
}

Вивід виглядатиме так:

Program begin!
Object created!
Program end!
Object destroyed!

На прикладі цієї програми ми бачимо, що статичний об'єкт було створено при першому виклику функції func(), а знищено вже після роботи програми. Зверніть увагу: навіть при другому виклику функції func() повторного створення об'єкту не відбулося.

Статичні об'єкти (оголошені як static) створюються лише один раз за час роботи програми і існують до кінця її роботи. Наприклад, якщо ми оголосимо змінну типу int у функції та присвоїмо їй якесь значення, то при наступному виклику ця змінна матиме те ж саме значення, яке ми їй присвоїли.

Last updated