CLOSE
Updated on 24 Jun, 202624 mins read 16 views

In the previous chapter, we learned:

Object = Identity + State + Behavior

We also learned:

class User
{
};

is merely a blueprint.

But an important question remains:

How does and object actually come into existence?

When you write:

User user;

what exactly happens?

Where is the object stored?

How is memory allocated?

Who initializes its state?

When is it destroyed?

Who free its memory?

What happens if initialization fails?

What if the object owns resources?

What if the object creates other objects?

Historical Context

Early programming languages often forced developers to manage memory manually.

Example:

malloc()
free()

Programmers were responsible for:

Allocate memory
Initialize memory
Track ownership
Release memory

This caused countless bugs:

Memory Leaks
Dangling Pointers
Double Free
Uninitialized Memory

C++ introduced a powerful concept:

Constructors and Destructors

which enabled automatic object lifecycle management.

This eventually evolved into one of C++'s greatest strengths:

RAII (Resource Acquisition Is Initialization)

The Lifecycle of an Object

Every object follows a lifecycle.

Creation
    ↓
Initialization
    ↓
Usage
    ↓
Destruction

Every object in C++ follows this journey.

Real-World Analogy: Hotel Guest

Consider a hotel.

Step 1: Arrival

Guest enters hotel.

Equivalent:

Object Creation

Step 2: Check-In

Room assigned.

Equivalent:

Initialization

Step 3: Stay

Guest uses room.

Equivalent:

Object Usage

Step 4: Checkout

Guest leaves.

Equivalent:

Object Destruction

Every object follows the same lifecycle.

What Is a Constructor?

A constructor is:

A special function responsible for initializing an object when it is created.

Syntax:

class User
{
public:

    User()
    {
    }
};

Notice:

Same name as class
No return type

Why Constructors Exist

Without constructors:

class User
{
public:

    std::string name;
    int age;
};

Creation:

User user;

What should:

name = ?
age = ?

be initialized to?

The object may start in an invalid state.

Constructors solve this problem.

Example:

class User
{
public:

    std::string name;
    int age;

    User()
    {
        name = "Unknown";
        age = 0;
    }
};

Now every User begins in a valid state.

Default Constructor

A constructor with no parameters.

class User
{
public:

    User()
    {
    }
};

Usage:

User user;

Parameterized Constructor

Allows initialization using values.

class User
{
public:

    std::string name;
    int age;

    User(std::string n, int a)
    {
        name = n;
        age = a;
    }
};

Usage:

User user("TheJat", 07);

Constructor Overloading

A class can have multiple constructors.

class User
{
public:

    User()
    {
    }

    User(std::string name)
    {
    }

    User(std::string name, int age)
    {
    }
};

C++ selects the matching constructor.

Initialization Lists

Professional C++ code uses initialization lists.

Instead of:

User(std::string n, int a)
{
    name = n;
    age = a;
}

Prefer:

User(std::string n, int a)
    : name(n),
      age(a)
{
}

Why?

Because:

Direct Initialization

instead of:

Default Construction
    +
Assignment

More efficient.

Object Creation in Memory

When an object is created:

User user("TheJat", 07);

two things happen:

Memory Allocated
      ↓
Constructor Executes

Important:

Allocation != Initialization

These are separate operations.

Stack Memory

Most objects are created on the stack.

Example:

void function()
{
    User user("TheJat", 07);
}

When function exists:

Object automatically destroyed

Benefits of Stack Allocation

Fast
Automatic Cleanup
No Memory Leaks

Preferred whenever possible.

Heap Memory

Objects can also be created dynamically.

User* user = new User("TheJat", 07);

Memory:

Stack
+---------+
| Pointer |
+---------+

Heap
+---------+
| User    |
+---------+

Important Difference

Stack:

Automatic Cleanup

Heap:

Manual Cleanup Required

Example:

delete user;

Failure to delete:

Memory Leak

Object Lifetime

Lifetime means:

The period during which an object exists.

Stack Object Lifetime

void process()
{
	User user;
}

Timeline:

Enter Function
     ↓
Create User
     ↓
Use User
     ↓
Exit Function
     ↓
Destroy User

Automatic.

Heap Object Lifetime

User* user = new User();

Timeline:

Create Object
      ↓
Use Object
      ↓
Delete Object
      ↓
Destroy Object

Controlled by programmer.

Destructor

Just as constructor creates objects:

Destructors clean them up.

Syntax:

class User
{
public:

    ~User()
    {
    }
};

Characteristics:

Starts with ~

No Parameters

No Return Type

Example:

class File
{
public:

    File()
    {
        std::cout << "Open File\n";
    }

    ~File()
    {
        std::cout << "Close File\n";
    }
};

Usage:

{
    File file;
}

Output:

Open File
Close File

Automatic cleanup.

Constructor and Destructor Order

Example:

class Engine
{
public:
    Engine()
    {
        std::cout << "Engine Created\n";
    }

    ~Engine()
    {
        std::cout << "Engine Destroyed\n";
    }
};
class Car
{
private:
    Engine engine;
};

Creation:

Engine Created
Car Created

Destruction:

Car Destroyed
Engine Destroyed

Reverse order.

// Example program
#include <iostream>
#include <string>

using namespace std;

class Engine {
public:
    Engine()
    {
        cout << "Engine constructor \n";
    }
    
    ~Engine()
    {
        cout << "Engine destructor \n";    
    }
};

class Car{
public:
    Engine engine;
    
    Car()
    {
        cout<< "Car Constructor \n";
    }
    
    ~Car()
    {
        cout<< "Car Destructor \n";
    }
};

int main()
{
  Car car1;
}
Engine constructor 
Car Constructor 
Car Destructor 
Engine destructor 

Ownership

One of the most important concepts in modern C++.

Question:

Who is responsible for cleanup?

Example:

User* user = new User();

Who deletes it?

Ownership determines responsibility.

Ownership Analogy

Imagine:

Car Owner

Owner responsible for:

Maintenance
Insurance
Repairs

Similarly:

Object Owner

Responsible for:

Creation
Lifecycle
Cleanup

Resource Management

Objects often own resources.

Example:

Files

Sockets

Database Connections

Threads

Locks

Not just memory.

Example:

class DatabaseConnection
{
};

Opening connection:

Resource Acquired

Closing connection:

Resource Released

Must always happen correctly.

The Problem of Manual Cleanup

Example:

DatabaseConnection* db =
    new DatabaseConnection();

processData();

delete db;

Looks fine.

But what if:

processData();

throws exception?

Then:

delete db;

never executes.

Resource leak.

Enter RAII

RAII means:

Resource Acquisition Is Initialization

Idea:

Acquire Resource in Constructor
Release Resource in Destructor

Example:

class File
{
public:

    File()
    {
        open();
    }

    ~File()
    {
        close();
    }
};

Now:

void process()
{
	File file;
}

Resource cleanup becomes automatic.

Why RAII Is Powerful

Without RAII:

Acquire Resource
Remember Cleanup
Hope Nothing Fails

With RAII:

Acquire Resource
Cleanup Automatic

Much safer.

 

Buy Me A Coffee

Leave a comment

Your email address will not be published. Required fields are marked *

Your experience on this site will be improved by allowing cookies Cookie Policy