Modern C++ owns resources with RAII, not manual new/delete. unique_ptr for single ownership, shared_ptr for shared ownership, and weak_ptr to break reference cycles.
Resource Acquisition Is Initialization is the central C++ idea: acquire a resource in a constructor, release it in the destructor. Because destructors run automatically when a scope ends — even if an exception is thrown — cleanup is guaranteed. This is what makes smart pointers, locks, and file handles safe.
#include <cstdio>
class File {
std::FILE* f_;
public:
explicit File(const char* path) : f_(std::fopen(path, "w")) {}
~File() { if (f_) std::fclose(f_); } // released automatically
void write(const char* s) { if (f_) std::fputs(s, f_); }
};
int main() {
File log("out.txt");
log.write("hello\n");
return 0; // ~File() runs here and closes the file
}A std::unique_ptr owns a heap object exclusively and deletes it automatically when it goes out of scope. It cannot be copied (only moved), which makes ownership unambiguous. Create one with std::make_unique. This should be your default owner.
#include <memory>
#include <iostream>
struct Widget {
int id;
Widget(int i) : id(i) { std::cout << "make " << id << "\n"; }
~Widget() { std::cout << "drop " << id << "\n"; }
};
int main() {
auto w = std::make_unique<Widget>(1);
std::cout << w->id << "\n"; // 1
auto w2 = std::move(w); // ownership transfers; w is now null
return 0; // "drop 1" prints here — no delete needed
}A std::shared_ptr lets several owners share one object; a reference count tracks them, and the object is freed when the last owner disappears. But two shared_ptrs pointing at each other form a cycle that never reaches zero — a leak. std::weak_ptr observes without owning, breaking the cycle.
#include <memory>
#include <iostream>
int main() {
auto a = std::make_shared<int>(42);
std::cout << a.use_count() << "\n"; // 1
{
auto b = a; // shared ownership
std::cout << a.use_count() << "\n"; // 2
} // b gone
std::cout << a.use_count() << "\n"; // 1
std::weak_ptr<int> w = a; // does NOT raise the count
if (auto locked = w.lock()) // promote to shared_ptr if alive
std::cout << *locked << "\n"; // 42
return 0;
}