Loading...

Constructors and Destructors in C++

Learn constructors and destructors in C++ to understand object lifetime, initialization, and resource management.

In C++, every class has special methods that are called when an object is created or destroyed: Constructor and Destructor. The constructor prepares the object for use, while the destructor cleans up memory. This structure forms the foundation of the RAII (Resource Acquisition Is Initialization) principle.


1. What Is a Constructor?

A constructor is a special method that is automatically called when an object of a class is created. Its purpose is to initialize variables and prepare the necessary resources.


class Book {
private:
    string title;
    int pages;

public:
    // Default constructor
    Book() {
        title = "Unknown";
        pages = 0;
        cout << "Default constructor called." << endl;
    }

    // Parameterized constructor
    Book(string t, int p) {
        title = t;
        pages = p;
        cout << "Parameterized constructor called." << endl;
    }

    void Display() {
        cout << "Book: " << title << " (" << pages << " pages)" << endl;
    }
};

The constructor runs automatically when the object is created:


int main() {
    Book b1;
    Book b2("C++ Programming", 900);

    b1.Display();
    b2.Display();
}

2. What Is a Destructor?

A destructor is a special method that is called when an object’s lifetime ends. It is used to perform cleanup operations such as freeing memory or closing files.


class Book {
public:
    Book() {
        cout << "Constructor executed." << endl;
    }

    ~Book() {
        cout << "Destructor executed." << endl;
    }
};

int main() {
    Book b;
} // Destructor is automatically called at the end of main

Output:


Constructor executed.
Destructor executed.

Since the destructor is called automatically, it should not be invoked manually.


3. Book Example: Extended Constructor and Destructor

Now let’s make the Book class more realistic. It will contain dynamically allocated data (for example, a book description). This will show why destructors are important.


#include <iostream>
#include <string>
using namespace std;

class Book {
private:
    string title;
    int pages;
    string *description; // Dynamic memory

public:
    // Constructor
    Book(string t, int p, string d)
        : title(t), pages(p) {
        description = new string(d);
        cout << "Book constructor: " << title << endl;
    }

    // Destructor
    ~Book() {
        cout << "Book destructor: " << title << endl;
        delete description; // Free dynamic memory
    }

    void Display() const {
        cout << "Book: " << title << " (" << pages << " pages)" << endl;
        cout << "Description: " << *description << endl;
    }
};

int main() {
    Book b1("1984", 328, "A dystopian novel.");
    b1.Display();
}

Output:


Book constructor: 1984
Book: 1984 (328 pages)
Description: A dystopian novel.
Book destructor: 1984

The destructor is called automatically when the object in main() goes out of scope and releases the memory allocated with new.


4. Constructor Overloading

Multiple constructors can be defined in the same class. The appropriate one is called based on the number and type of parameters.


class Book {
private:
    string title;
    int pages;

public:
    Book() : title("Unknown"), pages(0) {}
    Book(string t) : title(t), pages(100) {}
    Book(string t, int p) : title(t), pages(p) {}

    void Display() {
        cout << "Book: " << title << " (" << pages << " pages)" << endl;
    }
};

int main() {
    Book b1;
    Book b2("C++ 101");
    Book b3("Design Patterns", 450);

    b1.Display();
    b2.Display();
    b3.Display();
}

5. Copy Constructor

By default, C++ automatically creates a copy constructor, but if your class uses dynamic memory, you must define your own copy constructor.


class Book {
private:
    string title;
    string *desc;

public:
    Book(string t, string d) {
        title = t;
        desc = new string(d);
        cout << "Constructor: " << title << endl;
    }

    // Copy constructor
    Book(const Book &other) {
        title = other.title;
        desc = new string(*other.desc); // deep copy
        cout << "Copy constructor: " << title << endl;
    }

    ~Book() {
        delete desc;
        cout << "Destructor: " << title << endl;
    }

    void Display() {
        cout << title << " - " << *desc << endl;
    }
};

int main() {
    Book b1("C++ Primer", "Beginner's guide");
    Book b2 = b1; // copy constructor is called
    b2.Display();
}

If a deep copy is not performed, both objects will share the same memory, leading to a “double delete” error when the destructor is called.


6. Book System – Lifecycle Tracking

The following example shows the creation and destruction order of a book object. It’s ideal for understanding the actual lifecycle of constructors and destructors.


#include <iostream>
#include <string>
using namespace std;

class Author {
public:
    Author(string n) { cout << "Author created: " << n << endl; }
    ~Author() { cout << "Author destroyed." << endl; }
};

class Book {
private:
    string title;
    Author author;

public:
    Book(string t, string a) : title(t), author(a) {
        cout << "Book created: " << title << endl;
    }

    ~Book() {
        cout << "Book destroyed: " << title << endl;
    }
};

int main() {
    Book b("Animal Farm", "George Orwell");
}

Output:


Author created: George Orwell
Book created: Animal Farm
Book destroyed: Animal Farm
Author destroyed.

As you can see, the Author constructor is called first, followed by the Book constructor. During destruction, the reverse order occurs (Book first, then Author). This demonstrates the lifecycle order in composition relationships in C++.


7. TL;DR

  • Constructor → Automatically called when an object is created.
  • Destructor → Automatically called when an object’s lifecycle ends.
  • Constructors can be overloaded, destructors cannot.
  • If dynamic memory is used, the destructor must call delete.
  • The copy constructor should perform a deep copy.
  • Creation order: first subcomponents, then the class; Destruction order: first the class, then subcomponents.
  • All examples can be run in Visual Studio 2022 or GCC 11+ compilers.

Related Articles