Constructors & Destructors in C++

    Atul Kabra4 min readUpdated

    A constructor is a special member function that runs automatically when an object is created, putting it into a valid starting state. A destructor runs automatically when the object is destroyed, releasing anything it owns. Together they bookend an object's lifetime so you never have to remember to set up or tear down by hand.

    Here is the shape of both.

    A basic constructor

    A constructor has the same name as the class and no return type.

    #include <iostream>
    #include <string>
    
    class Student {
    public:
        std::string name;
        int rollNumber;
    
        // constructor: runs when a Student is created
        Student(std::string n, int r) {
            name = n;
            rollNumber = r;
            std::cout << "Created " << name << "\n";
        }
    };
    
    int main() {
        Student s{"Asha", 12};   // constructor is called here
        std::cout << s.name << " has roll " << s.rollNumber << "\n";
    }
    

    Output:

    Created Asha
    Asha has roll 12
    

    Member initializer lists (preferred)

    Assigning inside the body works, but the modern, more efficient way is a member initializer list — the part after the colon. Members are initialised directly instead of being default-built then reassigned.

    class Student {
    public:
        std::string name;
        int rollNumber;
    
        // initializer list: name and rollNumber are built directly
        Student(std::string n, int r)
            : name(std::move(n)), rollNumber(r) {}
    };
    

    Always prefer initializer lists, especially for const members and references, which cannot be assigned in the body.

    Default and parameterised constructors

    A class can have several constructors (this is overloading). A default constructor takes no arguments.

    class Counter {
    public:
        int value;
    
        Counter() : value(0) {}            // default constructor
        Counter(int start) : value(start) {} // parameterised
    };
    
    Counter a;        // value == 0
    Counter b{10};    // value == 10
    

    If you write no constructor at all, the compiler generates a default one for you. You can also ask for it explicitly with Counter() = default;.

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses

    The destructor

    A destructor is named ~ClassName, takes no arguments, and is called automatically when the object goes out of scope. It is where you release resources.

    #include <iostream>
    
    class FileLogger {
    public:
        FileLogger() { std::cout << "Logger opened\n"; }
        ~FileLogger() { std::cout << "Logger closed\n"; } // cleanup
    };
    
    int main() {
        FileLogger log;          // "Logger opened"
        std::cout << "Working...\n";
    }                            // "Logger closed" — destructor runs here
    

    This automatic cleanup is called RAII (Resource Acquisition Is Initialisation): acquire a resource in the constructor, release it in the destructor, and the object's lifetime guarantees it is always freed — even if an exception is thrown.

    Prefer smart pointers for owned memory

    When an object owns heap memory, do not pair raw new with manual delete in the destructor. Use a smart pointer; it cleans up for you and is exception-safe.

    #include <memory>
    #include <string>
    
    class Course {
        std::unique_ptr<std::string> title; // owns the string; auto-freed
    public:
        Course(std::string t)
            : title(std::make_unique<std::string>(std::move(t))) {}
        // no manual destructor needed — unique_ptr releases the memory
    };
    

    Common mistakes

    • Giving the constructor a return type. void Student(...) is not a constructor — it is an ordinary member function that happens to share the name.
    • Assigning in the body when an initializer list is required. const members and references must be set in the initializer list.
    • Pairing raw new with manual delete. Prefer std::unique_ptr / std::make_unique so cleanup is automatic and exception-safe.
    • Forgetting that the destructor runs on scope exit. Returning a pointer to a stack object whose destructor already ran is undefined behaviour.

    FAQ

    Can a class have more than one constructor? Yes. As long as their parameter lists differ, you can provide as many as you need (constructor overloading).

    When exactly does the destructor run? When the object's lifetime ends — for a local object, at the closing brace of its scope; for a heap object, when it is deleted (or when its smart pointer is destroyed).

    Keep learning

    Ready to practise with a mentor? Join the waitlist for our C++ Programming course in Jalgaon.

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses
    Atul Kabra

    Founder, Infoplanet

    Atul Kabra founded Infoplanet in 2001 and has spent over two decades teaching programming — C, C++, Java, databases and more — to students across Maharashtra.

    Related guides