Back to TILs

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.

The best example of why I shouldn’t be in marketing… I didn’t have a good day when I named that

A better name is probably:

  • Constructor Acquires, Destructor Releases

  • Scope Based Resource Management

    Bjarne Stroustrup (2012)

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

References