Skip to content

Object Lifecycle

Inheritance vs. Containers

It may happen that we want to store elements of a polymorphic type in some container. For example, we may want to store different types of Instrument objects such as Piano, Flute, Drum, etc. Every instrument can produce sound, but for an arbitrary Instrument object it is hard to tell how it will sound.

In such cases, the play() method of the Instrument class should be virtual, so each instrument can return its own specific sound.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <vector>

using namespace std;

class Instrument {
public:
  virtual void play() const {
    cout << "???" << endl;
  }
};

class Flute : public Instrument {
public:
  void play() const override {
    cout << "Trill-trill" << endl;
  }
};

int main() {
    vector<Instrument> container;
    Flute flute;
    container.push_back(flute);
    container[0].sound();
}

Output

???

The issue is visible: copying the Flute object by value into the vector behaves like pass-by-value. The object loses its derived properties, so the polymorphic call cannot take effect.

We could store references or pointers instead, but references cannot be placed into containers.

Object Management

In Java we have already seen that the program uses different memory regions. Until now, every object we created was created locally, on the stack. Such objects live only until the execution leaves the block in which they were created, at which point their destructors run and memory is freed.

To keep an object alive for the entire program, we could make it global, but this is usually bad practice.

In C++, we can create objects that outlive their creating block without being global, using dynamic allocation. However, unlike Java, C++ does not have a garbage collector — freeing memory is the programmer’s responsibility.

Dynamic Memory Management

Dynamic memory is allocated on the heap, which is larger than the stack but must be explicitly requested, is slower, and is not automatically managed. We use pointers to access dynamically allocated memory.

In C++ we use the new operator. On failure it throws std::bad_alloc. Example:

1
2
3
4
5
6
7
8
#include<iostream>
using namespace std;

int main() {
  int *p = new int;
  cin >> *p;
  cout << "Value at " << p << ": " << *p << endl;
}

We may also use new (nothrow) to avoid exceptions.

Arrays are allocated with new[], and freed with delete[].

1
2
int* array = new int[10];
delete[] array;

Summary

Allocated cells Operator Error handling Release
1 new try-catch delete
many new[] try-catch delete[]
1 new(nothrow) check pointer delete
many new(nothrow) check pointer delete[]

Dynamic Data Members in Classes

Classes often allocate memory dynamically for their internal data. Such memory must be released in the destructor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Course {
  string name, code;
  unsigned enrolled = 0;
  Student* students;
public:
  Course(const string& name, const string& code)
    : name(name), code(code), students(new Student[10]) {}

  ~Course() {
    delete[] students;
  }
};

Every new must correspond to a delete (or delete[]).

Inheritance vs. Containers Revisited

We can store employees and researchers in containers. Copying objects by value destroys polymorphism — only the base portion is copied.

Using pointers preserves polymorphism:

1
2
3
4
5
6
7
8
class University {
  vector<Employee*> employees;
public:
  University& operator+(Employee* e) {
    employees.push_back(e);
    return *this;
  }
};

Virtual Destructor

If we delete derived objects through a base-class pointer, the base destructor must be virtual, otherwise only the base destructor runs, and the derived part leaks memory.

Correct implementation:

1
2
3
4
5
class Employee {
public:
  virtual ~Employee() {}
  virtual void attendMeeting() const { cout << "Employee meeting" << endl; }
};

With a virtual destructor, deleting via a base pointer correctly invokes the derived destructor as well.


Last update: 2025-11-27
Created: 2025-11-27