How to Use Memory Management and Smart Pointers in C++

memory-management-smart-pointer

In this tutorial, we will explore memory management and smart pointers in C++. 

Prerequisites

Managing Memory with malloc 

Let’s explore memory management in C++ using malloc and free. Understanding manual memory management is crucial for robotics programming, especially in resource-constrained environments. 

Open a terminal window, and type this: 

cd ~/Documents/cpp_tutorial 
code . 

Create a new C++ file and name it memory_management_example.cpp

Type the following code into the editor:

#include <iostream>
#include <cstdlib>  // For malloc and free

int main() {
    int *ptr = (int*) malloc(sizeof(int));  // Allocating memory for an integer
    if (ptr == nullptr) {
        std::cout << "Memory allocation failed" << std::endl;
        return -1;  // Return an error if memory allocation failed
    }
    
    *ptr = 5;  // Assigning value to the allocated memory
    std::cout << "Value at pointer: " << *ptr << std::endl;

    free(ptr);  // Freeing the allocated memory
    ptr = nullptr;  // Setting pointer to nullptr after freeing memory

    return 0;
}

In this code snippet, we use malloc to allocate memory for an integer and check if the memory allocation was successful. We then assign a value to this memory, print it, and finally, free the memory using free to avoid memory leaks. 

Setting the pointer to nullptr after freeing is a good practice to prevent dangling pointers.

Run the code.

1-memory-management

You should see the output “Value at pointer: 5”, confirming that our memory management operations are functioning correctly.

Using Smart Pointers

Let’s explore smart pointers in C++, which provide automatic memory management and help prevent memory leaks. We’ll look at unique_ptr, shared_ptr, and weak_ptr, which are part of modern C++’s memory management toolkit. 

Create a new C++ file and name it smart_pointers.cpp

Type the following code into the editor:

#include <iostream>
#include <memory>

// Sensor class representing a sensor with a name and a value
class Sensor {
private:
    std::string name;
    double value;

public:
    Sensor(const std::string& name, double value) : name(name), value(value) {}

    void printInfo() const {
        std::cout << "Sensor: " << name << ", Value: " << value << std::endl;
    }
};

int main() {
    // Create a unique_ptr to a Sensor object
    std::unique_ptr<Sensor> sensor1 = std::make_unique<Sensor>("TemperatureSensor", 25.5);
    sensor1->printInfo();

    // Create a shared_ptr to a Sensor object
    std::shared_ptr<Sensor> sensor2 = std::make_shared<Sensor>("HumiditySensor", 60.0);
    sensor2->printInfo();

    // Create a weak_ptr to the shared_ptr
    std::weak_ptr<Sensor> weak_sensor = sensor2;
    if (auto shared_sensor = weak_sensor.lock()) {
        shared_sensor->printInfo();
    }

    return 0;
}

In this code, we define a Sensor class that represents a sensor with a name and a value.

In the main() function, we demonstrate the usage of different smart pointers:

  • unique_ptr: We create a unique_ptr to a Sensor object using std::make_unique(). The unique_ptr ensures exclusive ownership and automatically deletes the object when it goes out of scope.
  • shared_ptr: We create a shared_ptr to a Sensor object using std::make_shared(). The shared_ptr allows multiple pointers to share ownership of the object. The object is deleted when all shared_ptr instances go out of scope.
  • weak_ptr: We create a weak_ptr to the shared_ptr. The weak_ptr does not participate in ownership but can be used to check if the object is still valid. We use lock() to obtain a shared_ptr from the weak_ptr and access the object.

Run the code.

2-smart-pointers

The output displays the information of the Sensor objects created using smart pointers.

This example demonstrates how to use smart pointers in C++ for robotics projects. Smart pointers provide automatic memory management, helping to prevent memory leaks and simplify memory ownership. They are particularly useful when dealing with dynamically allocated objects and help make the code more robust and maintainable.

Thanks, and I’ll see you in the next tutorial.

Keep building!