A destructor ~T() runs automatically when an object's lifetime ends. RAII ties a resource (memory, file, lock, socket) to an object so the destructor always releases it — even when an exception is thrown.
Destructor basics
#include <iostream>
#include <string>
struct Noisy {
std::string name;
explicit Noisy(std::string n) : name(std::move(n)) { std::cout << "ctor " << name << '\n'; }
~Noisy() { std::cout << "dtor " << name << '\n'; }
};
int main() {
Noisy a("a");
{
Noisy b("b");
Noisy c("c");
} // c then b destroyed here — reverse order
Noisy d("d");
std::cout << "end of main\n";
} // d then actor a
ctor b
ctor c
dtor c
dtor b
ctor d
end of main
dtor d
dtor aWriting an RAII wrapper
#include <cstdio>
#include <iostream>
#include <stdexcept>
class File {
std::FILE* f_;
public:
File(const char* path, const char* mode) : f_(std::fopen(path, mode)) {
if (!f_) throw std::runtime_error("cannot open file");
}
~File() { std::fclose(f_); std::cout << "file closed\n"; }
File(const File&) = delete; // one owner only
File& operator=(const File&) = delete;
std::FILE* get() const { return f_; }
};
void process() {
File out("raii_demo.txt", "w");
std::fputs("hello\n", out.get());
throw std::runtime_error("something failed"); // destructor still closes the file
}
int main() {
try { process(); } catch (const std::exception& e) { std::cout << "caught: " << e.what() << '\n'; }
std::remove("raii_demo.txt");
}file closed
caught: something failedScope guards
#include <iostream>
#include <utility>
template <class F>
class ScopeExit { // run any cleanup when the scope ends
F fn_;
public:
explicit ScopeExit(F fn) : fn_(std::move(fn)) {}
~ScopeExit() { fn_(); }
ScopeExit(const ScopeExit&) = delete;
ScopeExit& operator=(const ScopeExit&) = delete;
};
int main() {
int depth = 0;
{
++depth;
ScopeExit restore([&] { --depth; std::cout << "restored\n"; });
std::cout << "depth " << depth << '\n';
}
std::cout << "depth " << depth << '\n';
}depth 1
restored
depth 0Why doesn't C++ need a garbage collector?
When is a destructor called?