destructor


Concept: Destructors

In C++, a destructor is a special member function of a class that is automatically called when an object of that class goes out of scope or is explicitly deleted. Destructors play a crucial role in resource management and are essential for implementing proper cleanup procedures.

Key Characteristics

Example 1: Basic Usage

#include <iostream>

class SimpleClass {
public:
    SimpleClass() {
        std::cout << "Constructor called" << std::endl;
    }

    ~SimpleClass() {
        std::cout << "Destructor called" << std::endl;
    }
};

int main() {
    {
        SimpleClass obj;
    } // obj goes out of scope here

    std::cout << "After inner scope" << std::endl;
    return 0;
}

Explanation:

Example 2: Resource Management

#include <iostream>
#include <cstring>

class DynamicString {
private:
    char* data;

public:
    DynamicString(const char* str) {
        data = new char[strlen(str) + 1];
        strcpy(data, str);
        std::cout << "String created: " << data << std::endl;
    }

    ~DynamicString() {
        std::cout << "Deleting string: " << data << std::endl;
        delete[] data;
    }

    const char* getData() const { return data; }
};

int main() {
    DynamicString str1("Hello");
    {
        DynamicString str2("World");
        std::cout << str1.getData() << " " << str2.getData() << std::endl;
    } // str2 is destroyed here
    std::cout << "After inner scope" << std::endl;
    return 0;
} // str1 is destroyed here

Explanation:

Example 3: Virtual Destructors in Inheritance

#include <iostream>

class Base {
public:
    Base() { std::cout << "Base constructor" << std::endl; }
    virtual ~Base() { std::cout << "Base destructor" << std::endl; }
};

class Derived : public Base {
public:
    Derived() { std::cout << "Derived constructor" << std::endl; }
    ~Derived() { std::cout << "Derived destructor" << std::endl; }
};

int main() {
    Base* ptr = new Derived();
    delete ptr;
    return 0;
}

Explanation:

Example 4: Destructor in RAII (Resource Acquisition Is Initialization)

#include <iostream>
#include <fstream>
#include <stdexcept>

class FileHandler {
private:
    std::ofstream file;

public:
    FileHandler(const std::string& filename) {
        file.open(filename);
        if (!file.is_open()) {
            throw std::runtime_error("Unable to open file");
        }
        std::cout << "File opened" << std::endl;
    }

    ~FileHandler() {
        if (file.is_open()) {
            file.close();
            std::cout << "File closed" << std::endl;
        }
    }

    void write(const std::string& data) {
        file << data;
    }
};

int main() {
    try {
        FileHandler fh("example.txt");
        fh.write("Hello, World!");
        // File is automatically closed when fh goes out of scope
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
    return 0;
}

Explanation:

Additional Considerations

  1. Order of Destruction: When an object contains member objects, the destructor of the containing class is called first, followed by the destructors of the member objects in the reverse order of their declaration.

  2. Exception Safety: Destructors should not throw exceptions. If an exception is thrown from a destructor during stack unwinding (e.g., when another exception is being handled), the program will terminate.

  3. Explicit Destruction: While objects are typically destroyed automatically, you can also call the destructor explicitly using the delete keyword for dynamically allocated objects.

Summary

Destructors in C++ are fundamental to proper resource management and object lifecycle. They automatically clean up resources when objects go out of scope, preventing memory leaks and other resource-related issues. Key points to remember:

Mastering the use of destructors is essential for writing robust, resource-efficient C++ code, especially in larger and more complex applications where resource management is critical.

Related

Previous Page | Course Schedule | Course Content