Tutorial on C++ Smart Pointers

in #blog6 days ago

Tutorial on Smart Pointers in C++

Smart pointers in C++ provide automatic and safe memory management. They help avoid memory leaks and dangling pointers by ensuring proper object destruction through RAII (Resource Acquisition Is Initialization).

This tutorial covers the three primary smart pointers in C++:

  • std::unique_ptr
  • std::shared_ptr
  • std::weak_ptr

1. std::unique_ptr

unique_ptr has exclusive ownership. Only one unique pointer can own a resource at a time.

Example: Owning a Simple Object

#include <iostream>
#include <memory>

int main() {
    std::unique_ptr<int> p = std::make_unique<int>(42);
    std::cout << "Value: " << *p << "\n";

    // Transfer ownership
    std::unique_ptr<int> q = std::move(p);
    if (!p) std::cout << "p is now null\n";
    std::cout << "q points to: " << *q << "\n";
}

Example: Building a Linked List

struct Node {
    int val;
    std::unique_ptr<Node> next;
    Node(int v) : val(v), next(nullptr) {}
};

void printList(const std::unique_ptr<Node>& head) {
    const Node* curr = head.get();
    while (curr) {
        std::cout << curr->val << " ";
        curr = curr->next.get();
    }
    std::cout << "\n";
}

int main() {
    auto head = std::make_unique<Node>(1);
    head->next = std::make_unique<Node>(2);
    head->next->next = std::make_unique<Node>(3);

    printList(head);
}

2. std::shared_ptr

shared_ptr allows multiple owners of a resource. It maintains a reference count and deletes the object when the last reference is gone.

Example: Shared Ownership

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> a = std::make_shared<int>(100);
    std::shared_ptr<int> b = a;

    std::cout << "a use count: " << a.use_count() << "\n";
    std::cout << "b use count: " << b.use_count() << "\n";
    std::cout << "*b = " << *b << "\n";
}

Example: Shared Linked List

struct Node {
    int val;
    std::shared_ptr<Node> next;
    Node(int v) : val(v), next(nullptr) {}
};

3. std::weak_ptr

weak_ptr is a non-owning reference to an object managed by shared_ptr. It is used to prevent circular references that lead to memory leaks.

Example: Breaking a Circular Reference

#include <iostream>
#include <memory>

struct B;

struct A {
    std::shared_ptr<B> b_ptr;
    ~A() { std::cout << "A destroyed\n"; }
};

struct B {
    std::weak_ptr<A> a_ptr;
    ~B() { std::cout << "B destroyed\n"; }
};

int main() {
    auto a = std::make_shared<A>();
    auto b = std::make_shared<B>();
    a->b_ptr = b;
    b->a_ptr = a;
}

Is There a make_weak?

No, there is no std::make_weak. This is because weak_ptr does not own memory and must point to an existing shared_ptr.

How to Create a weak_ptr

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sp = std::make_shared<int>(42);
    std::weak_ptr<int> wp = sp;

    if (auto locked = wp.lock()) {
        std::cout << "Value: " << *locked << "\n";
    } else {
        std::cout << "Object no longer exists\n";
    }
}

Summary

Smart Pointer Ownership Thread Safe Ref Counting Use Case
unique_ptr Exclusive N/A Fast, safe, sole ownership
shared_ptr Shared Yes Shared ownership
weak_ptr None N/A Break circular refs in shared_ptr

Reposted to Blog

--EOF (The Ultimate Computing & Technology Blog) --

Steem to the Moon🚀!