Constructors, Destructors & RAII

Constructor, destructor ও RAII

Read: ~40 min 18 practice problems

1. Constructors — How Objects Begin Life

A constructor sets up an object. It runs once, when the object is created.

ctor.cpp
#include <iostream>
#include <string>

class Box {
    int w_, h_;
public:
    Box() : w_(1), h_(1) { std::cout << "default\n"; }
    Box(int w, int h) : w_(w), h_(h) { std::cout << "sized\n"; }
    int area() const { return w_ * h_; }
};

int main() {
    Box a;            // default
    Box b{3, 4};       // parameterized
    std::cout << a.area() << " " << b.area() << "\n";
}

2. The Six Special Member Functions

MemberSignaturePurpose
Default ctorT()Construct with no args
Destructor~T()Clean up resources
Copy ctorT(const T&)Construct from another
Copy assignoperator=(const T&)Assign from another
Move ctorT(T&&)Steal from temporary
Move assignoperator=(T&&)Move-assign from temp

3. Destructor & RAII

The destructor runs automatically when the object's lifetime ends. This is RAII's hammer:

raii.cpp
#include <iostream>
#include <fstream>

class File {
    std::FILE* f_ = nullptr;
public:
    File(const char* path, const char* mode) {
        f_ = std::fopen(path, mode);
        if (!f_) throw std::runtime_error{"open failed"};
    }
    ~File() { if (f_) std::fclose(f_); }   // auto cleanup!

    File(const File&) = delete;             // non-copyable
    File& operator=(const File&) = delete;
};
RAII pattern Acquire the resource in the constructor, release it in the destructor. The compiler guarantees the destructor runs — even on exceptions. Leaks become impossible.

4. Member Initialization List

Always prefer the member init list over assignment in the constructor body:

init.cpp
// Good — init list
Person(std::string n, int a) : name_(std::move(n)), age_(a) {}

// Bad — body assignment (members default-constructed first, then overwritten)
Person(std::string n, int a) {
    name_ = n;
    age_ = a;
}

For const and reference members, the init list is the only option.

5. Object Lifecycle Demo

lifecycle.cpp
#include <iostream>

struct Tracer {
    Tracer()                { std::cout << "ctor\n"; }
    Tracer(const Tracer&) { std::cout << "copy\n"; }
    Tracer(Tracer&&) noexcept { std::cout << "move\n"; }
    ~Tracer()               { std::cout << "dtor\n"; }
};

Tracer make() { return Tracer{}; }

int main() {
    Tracer a;
    Tracer b = make();
    Tracer c = a;
}

6. Practice Problems

  1. Write a default constructor for a class.
    ✨ Show Answer
    MyClass() {} // or = default;
  2. When does the destructor run?
    ✨ Show Answer

    (1) Local objects: when their scope ends. (2) Heap objects: on delete. (3) Members: when their containing object is destroyed. (4) Temporaries: at the end of the full expression.

  3. Why use a member init list?
    ✨ Show Answer

    More efficient (no default-construct-then-assign), and required for const/reference members.

  4. Define a class that opens a socket in ctor and closes in dtor.
    ✨ Show Answer

    See File example above. Same pattern: acquire in ctor, release in dtor, delete copies.

  5. What does = default do?
    ✨ Show Answer

    Asks the compiler to generate the default implementation of a special member function. Useful when you've declared others and lost the implicit defaults.

  6. What does = delete do?
    ✨ Show Answer

    Forbids that operation. T(const T&) = delete; makes the class non-copyable.

  7. When is the move ctor called?
    ✨ Show Answer

    When constructing from a rvalue (temporary or std::move(x)). Steals resources instead of copying.

  8. Why must destructors typically not throw?
    ✨ Show Answer

    If a destructor throws during stack unwinding (caused by another exception), std::terminate is called. Mark destructors noexcept (the default) and don't throw from them.

  9. Add a logging line in the constructor of class X.
    ✨ Show Answer
    X() { std::cout << "X created\n"; }
  10. Difference between T x; and T x{};?
    ✨ Show Answer

    T x; default-initializes (built-ins are uninitialized). T x{}; value-initializes (built-ins zero-out).

  11. What's a delegating constructor?
    ✨ Show Answer
    class X {
        int a, b;
    public:
        X() : X(0, 0) {}            // delegates to next
        X(int a, int b) : a(a), b(b) {}
    };
  12. Why is the destructor called for an object thrown out of scope by an exception?
    ✨ Show Answer

    Stack unwinding. When an exception propagates, all local objects in scope have their destructors called. RAII relies on this.

  13. What's an explicit constructor?
    ✨ Show Answer
    class X {
    public:
        explicit X(int);  // no implicit conversion
    };
    // X x = 5;     // ERROR
    // X x{5};      // OK
  14. When is the implicit copy constructor generated?
    ✨ Show Answer

    When you don't declare any of: copy ctor, move ctor, copy assign, move assign, destructor. If you declare any, the auto-generation rules get trickier — see Rule of Five (Module 24).

  15. Construct an object inside a vector with emplace_back.
    ✨ Show Answer
    std::vector<Person> v;
    v.emplace_back("Sara", 21); // constructs in-place
  16. Why prefer emplace_back over push_back?
    ✨ Show Answer

    emplace_back forwards arguments to construct the element in-place. push_back requires a constructed object first, then copies/moves it.

  17. Show that destructors run in reverse order of construction.
    ✨ Show Answer
    {
        Tracer a;
        Tracer b;
        Tracer c;
    } // dtors run: c, b, a
  18. When NOT to write a destructor?
    ✨ Show Answer

    When all members already manage their own resources (smart pointers, vectors, strings). The compiler-generated destructor calls each member's destructor automatically. This is the "Rule of Zero" — the cleanest design.

Summary

Constructors initialize, destructors clean up. RAII ties resources to lifetimes, making cleanup automatic and exception-safe. Always use member init lists. Aim for the Rule of Zero — let your members manage their own resources, and you write nothing special.

Next Module → Inheritance & Polymorphism.