C++: The Lifecycle, Constructors and Destructors

Understand how objects are born with constructors, cloned with copy constructors, and cleaned up with destructors.

The Object Lifecycle

Every object in C++ goes through three stages: creation, use, and destruction. Constructors handle creation, giving members their initial values the moment the object comes into existence. Destructors handle destruction, releasing any resources the object holds before it disappears from memory.

Three Stages of an Object

C++ gives you explicit control over each stage. You decide what happens at birth, what can be copied, and what gets cleaned up at death.

  • Creation: constructor runs automatically when the object is declared
  • Use: member functions read and modify the object's state
  • Destruction: destructor runs automatically when the object goes out of scope
  • For stack objects, destruction is guaranteed and predictable, no manual cleanup needed

Default Constructor

A default constructor takes no arguments. It runs whenever an object is created without providing any values. If you define no constructor at all, the compiler generates one that does nothing. Defining your own default constructor lets you set safe starting values for every member.

Default Constructor

A default constructor guarantees that every object starts with known, valid values instead of whatever happens to be in memory.

  • No parameters: ClassName() { }
  • Called when you write: Student s; or Student s{};
  • If you later define a parameterized constructor, the compiler no longer generates the default one, you must write it yourself if you still need it
  • Use member initializer lists (: member(value)) for cleaner initialization

Default Constructor

C++

Student s; triggers the default constructor, setting name and age to safe starting values.

Parameterized Constructor

A parameterized constructor accepts arguments so the caller can supply custom values at the moment of creation. This removes the need to assign members in a separate step and ensures the object is fully initialized right away.

Parameterized Constructor

Pass values directly at creation time. The object is ready to use immediately, with no risk of forgetting to set a member.

  • Syntax: ClassName(type param1, type param2) { members = params; }
  • Called when you write: Student s("Alice", 20);
  • Can be combined with a default constructor, both can coexist in the same class
  • Initializer list syntax is preferred: Student(string n, int a) : name(n), age(a) {}

Parameterized Constructor

C++

Each Student is created fully initialized. The initializer list sets members before the body runs.

Copy Constructor

A copy constructor creates a new object as a duplicate of an existing one. The compiler generates a default copy constructor that copies every member by value, which works fine for simple types. You write your own when the class manages heap memory, file handles, or other resources that require a deep copy.

Copy Constructor

The copy constructor signature always takes a const reference to the same class: ClassName(const ClassName& other).

  • Triggered by: Student s2 = s1; or Student s2(s1);
  • Also called when an object is passed by value to a function
  • The compiler's auto-generated version does a shallow (member-by-member) copy
  • Write your own for classes that own heap memory to avoid two objects pointing to the same allocation

Copy Constructor

C++

s2 is a new independent object. Changing s2.name does not affect s1.

All Three Constructors in One Class

A class can define all three constructor types at once. The compiler picks the right one based on how you create the object: no arguments calls the default, arguments call the parameterized, and initializing from an existing object calls the copy constructor.

Constructor Overloading

Providing multiple constructors gives callers flexibility: they can create a blank object, a fully specified one, or a clone of an existing one.

  • Default: Student s;
  • Parameterized: Student s("Carol", 21);
  • Copy: Student s2(s1); or Student s2 = s1;
  • The compiler resolves which constructor to call by matching the argument list

Three Constructor Types

C++

One class, three ways to create objects. Each constructor handles a different creation scenario.

Destructors

A destructor is the counterpart of a constructor. It runs automatically when an object goes out of scope or is deleted. Its job is to release any resources the object acquired during its lifetime, heap memory, open file handles, network connections, and so on. A class can have exactly one destructor and it takes no parameters.

Destructor

If a class allocates memory with new inside a constructor, the destructor must release it with delete to prevent a memory leak.

  • Syntax: ~ClassName() { cleanup code; }
  • No parameters, no return type, no overloading, exactly one per class
  • Called automatically: for stack objects when the scope ends; for heap objects when delete is called
  • The compiler generates a default destructor that does nothing, write your own when resources need freeing

Destructor in Action

C++

Watch the Closing messages appear automatically as each object leaves scope.

Destruction Order

Stack objects are destroyed in the reverse order of their creation (last in, first out). This mirrors how a call stack unwinds. Understanding this order matters when objects depend on one another or share a resource.

LIFO Destruction

Last created, first destroyed. C++ enforces this order so that dependent objects are always cleaned up before the objects they depend on.

  • If a is created before b, then b is destroyed before a
  • The same rule applies to local variables inside a function
  • Heap objects (created with new) are destroyed only when delete is called, order is up to you
  • This predictable order is why destructors are a reliable place to release resources

Reverse Destruction Order

C++

Bob is destroyed before Alice because he was created last.

Destructor with Heap Memory

When a constructor allocates memory with new, the destructor must free it with delete. Failing to do so causes a memory leak: the memory is never returned to the system for the lifetime of the program.

Destructor and new/delete

Every new in a constructor should have a matching delete in the destructor. Missing delete means leaked memory that accumulates until the program exits.

  • Constructor: data = new int[size]; allocates heap memory
  • Destructor: delete[] data; frees it
  • Without the destructor, the memory is orphaned and can never be reclaimed
  • Modern C++ prefers smart pointers (unique_ptr) to avoid manual delete entirely

Destructor Frees Heap Memory

C++

new in the constructor pairs with delete[] in the destructor to prevent a memory leak.

Knowledge Check

1. What is the return type of a constructor?

2. When is the default constructor called?

3. What does a copy constructor receive as its parameter?

4. When is a destructor automatically called?

5. What is the syntax for a destructor of class MyClass?

6. How many destructors can a class have?

7. If you define a parameterized constructor but no default constructor, what happens when you write: Student s;

8. What is a constructor initializer list used for?