Swiftorial Logo
Home
Swift Lessons
Tutorials
Learn More
Career
Resources

Smart Pointers in C++

Introduction

Smart pointers are a feature of C++ that provides automatic memory management. They help to prevent memory leaks by automatically deleting dynamically allocated memory when it is no longer needed. Smart pointers are defined in the <memory> header file and include several types, such as std::unique_ptr, std::shared_ptr, and std::weak_ptr.

std::unique_ptr

The std::unique_ptr is a smart pointer that owns and manages another object through a pointer. It ensures that the object is deleted when the std::unique_ptr goes out of scope. Only one std::unique_ptr can own a given object at a time.

#include <iostream>
#include <memory>

void uniquePtrExample() {
    std::unique_ptr<int> p1(new int(10));
    std::cout << *p1 << std::endl;

    // std::unique_ptr<int> p2 = p1; // Error: cannot copy unique_ptr
    std::unique_ptr<int> p2 = std::move(p1); // Transfer ownership
    std::cout << (p1 ? "p1 is not null" : "p1 is null") << std::endl;
    std::cout << *p2 << std::endl;
}

int main() {
    uniquePtrExample();
    return 0;
}
                

In the example above, we create a std::unique_ptr named p1 that manages a dynamically allocated integer. We then transfer ownership to p2 using std::move. After this transfer, p1 becomes null, and p2 owns the integer.

std::shared_ptr

The std::shared_ptr is a smart pointer that manages a shared ownership of an object. Multiple std::shared_ptr instances can own the same object. The object is destroyed when the last std::shared_ptr owning it is destroyed or reset.

#include <iostream>
#include <memory>

void sharedPtrExample() {
    std::shared_ptr<int> p1(new int(20));
    std::cout << *p1 << std::endl;
    std::cout << "p1 use count: " << p1.use_count() << std::endl;

    std::shared_ptr<int> p2 = p1; // Shared ownership
    std::cout << "p1 use count: " << p1.use_count() << std::endl;
    std::cout << "p2 use count: " << p2.use_count() << std::endl;
}

int main() {
    sharedPtrExample();
    return 0;
}
                

In this example, both p1 and p2 share ownership of the dynamically allocated integer. The use_count method returns the number of std::shared_ptr instances that own the object.

std::weak_ptr

The std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr. It is used to break circular references that can occur with std::shared_ptr.

#include <iostream>
#include <memory>

void weakPtrExample() {
    std::shared_ptr<int> p1 = std::make_shared<int>(30);
    std::weak_ptr<int> wp = p1;

    std::cout << "p1 use count: " << p1.use_count() << std::endl;
    {
        std::shared_ptr<int> p2 = wp.lock();
        if (p2) {
            std::cout << *p2 << std::endl;
            std::cout << "p2 use count: " << p2.use_count() << std::endl;
        } else {
            std::cout << "p2 is null" << std::endl;
        }
    }
    std::cout << "p1 use count: " << p1.use_count() << std::endl;
}

int main() {
    weakPtrExample();
    return 0;
}
                

In this example, we use std::weak_ptr to hold a weak reference to an integer managed by std::shared_ptr. The lock method of std::weak_ptr returns a std::shared_ptr if the managed object still exists, or a null pointer if it has been destroyed.

Conclusion

Smart pointers in C++ provide a convenient and safe way to manage dynamic memory. By using std::unique_ptr, std::shared_ptr, and std::weak_ptr, you can avoid common pitfalls such as memory leaks and dangling pointers. Understanding and utilizing smart pointers is essential for writing robust and maintainable C++ code.