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.
#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;
}
~SimpleClass()
is defined within the classobj
goes out of scope at the end of the inner block, the destructor is automatically called#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
DynamicString
class allocates memory in its constructor~DynamicString()
is responsible for freeing this allocated memorystr1
and str2
when they go out of scope#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;
}
Base
has a virtual destructorDerived
class inherits from Base
and overrides the destructorBase
pointer to delete a Derived
object calls both destructors correctlyBase
, only the Base
destructor would be called, leading to potential resource leaks#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;
}
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.
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.
Explicit Destruction: While objects are typically destroyed automatically, you can also call the destructor explicitly using the delete
keyword for dynamically allocated objects.
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.