Writing memory safe C++
Date: 2023-01-02Last modified: 2024-11-02
Table of contents
A base class for our experiments:
class MyClass {
public:
MyClass(const std::string &tag) : mTag(tag) {
fmt::print("{} - ✅ MyClass constructor was called\n", mTag);
}
~MyClass() { fmt::print("{} - ❌ MyClass destructor was called\n", mTag); }
private:
std::string mTag; // helps to identify the output line
};
RAII — Resource Acquisition Is Initialisatio
RAII is a bad name for the concept.
void raii() {
MyClass m0("raii 00");
{ MyClass m("raii 01"); }
{
auto m = new MyClass("raii 02");
delete m;
}
{ std::unique_ptr<MyClass> m(new MyClass("raii 03")); }
{ std::shared_ptr<MyClass> m(new MyClass("raii 04")); }
{
auto m = std::make_shared<MyClass>("raii 05");
auto m2 = m;
}
{
auto m = std::make_unique<MyClass>("raii 06");
fmt::print("raii 06 auto m2 = std::move(m);\n");
auto m2 = std::move(m);
fmt::print("raii 06 m is nullptr -> {}\n", m == nullptr);
fmt::print("raii 06 m2 is nullptr -> {}\n", m2 == nullptr);
}
// m0 will be freed here
}
Smart pointers
Avoid using dynamic memory and heap
Rule of Zero
Rule of Five
Rule of Three
If you implement a copy constructor, assignment operator, or destructor, you should implement the others, as well
raii();
Possible output
raii 00 - ✅ MyClass constructor was called
raii 01 - ✅ MyClass constructor was called
raii 01 - ❌ MyClass destructor was called
raii 02 - ✅ MyClass constructor was called
raii 02 - ❌ MyClass destructor was called
raii 03 - ✅ MyClass constructor was called
raii 03 - ❌ MyClass destructor was called
raii 04 - ✅ MyClass constructor was called
raii 04 - ❌ MyClass destructor was called
raii 05 - ✅ MyClass constructor was called
raii 05 - ❌ MyClass destructor was called
raii 06 - ✅ MyClass constructor was called
raii 06 auto m2 = std::move(m);
raii 06 m is nullptr -> true
raii 06 m2 is nullptr -> false
raii 06 - ❌ MyClass destructor was called
raii 00 - ❌ MyClass destructor was called