Published on

Writing Memory Safe C++ Code

Authors
  • avatar
    Name
    Skim
    Twitter

This article by Jacob Beningo discusses the recent recommendation by the NSA to use memory-safe programming languages and how this has sparked discussions about the use of languages like Rust in the embedded systems space. While memory-safe languages can reduce memory-related bugs, they are not a universal solution. Developers can still encounter memory issues even when using such languages. He addresses the challenges in adopting memory-safe languages in the embedded space, including the time and cost involved in training engineers, dealing with legacy code, and ensuring compatibility with existing vendor toolchains. He argues that for many teams, switching to a memory-safe language might be unnecessary.

A few C++ techniques that can help developers improve memory safety presented in the article are:

  1. Use smart pointers instead of raw pointers. Smart pointers manage allocation and deallocation automatically, avoiding the leaks that raw pointers commonly cause.
  2. Avoid dynamic memory and the heap when possible. Dynamic allocation introduces bugs like leaks and fragmentation. Disabling features like the STL and exceptions can help here.
  3. Apply RAII (Resource Acquisition Is Initialization) when you must use dynamic memory. RAII ties an object's lifecycle to its resources, so resources are freed automatically when the object goes out of scope.

The Rule of Zero, Rule of Three, and Rule of Five

These are guidelines for managing resources in C++ classes that handle memory, files, or other resources.

The Rule of Zero:

Avoid manually managing resources whenever possible. Prefer smart pointers (std::shared_ptr, std::unique_ptr) and standard library containers (std::vector, std::string) that handle their own cleanup. If you don't manage resources manually, you don't need custom destructors or copy/move operators.

The Rule of Three

If your class needs a custom destructor, copy constructor, or copy assignment operator, you probably need all three. The three special functions are:

  1. Destructor: To release resources held by an object when it goes out of scope.
  2. Copy Constructor: To create a deep copy of an object when you copy it.
  3. Copy Assignment Operator: To assign the contents of one object to another.

Defining any one of these usually means your class manages resources, so you need all three. In modern C++, this rule extends to the Rule of Five.

The Rule of Five

The Rule of Five extends the Rule of Three to include move semantics from C++11:

  1. Destructor
  2. Copy Constructor
  3. Copy Assignment Operator
  4. Move Constructor: Allows the efficient transfer of resources from one object to another.
  5. Move Assignment Operator: Allows efficient resource transfer during assignment.

If your class manages resources and defines any of these five, define all five.