Smart Pointers in C++: What Are They and When to Use Them? Tutorial

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Did Your Program "Eat" All the Memory and How to Fix It?

\n\n

Have you ever written a C++ application that worked perfectly until you closed the window? And then discovered it had "eaten" a gigabyte of RAM and returned not a single byte? Or, even worse, your program suddenly crashed with a mysterious segmentation fault, and you spent hours searching for where you forgot to call delete?

\n\n

If so — welcome to the club. Manual memory management in C++ is like juggling chainsaws: it's possible, but it's better to leave it to the professionals. Or, in our case, to smart pointers.

\n\n

Today we'll break down what these creatures are, what types exist, and most importantly, when to use which one. This material is an adaptation of a famous Stack Overflow question that has garnered thousands of views. We'll make it clear, lively, and with examples. Let's go!

\n\n

What is a Smart Pointer? In Simple Terms

\n\n

Imagine a regular pointer (int* ptr = new int(5);). It's like a key to a storage room with resources. You opened the storage room (allocated memory), but if you lose the key or forget to close the door — the resources are lost forever. That's a memory leak.

\n\n

A smart pointer is a "self-closing key." It's a wrapper class that stores a regular pointer inside and automatically calls delete (or delete[]) when the object is no longer needed. When the smart pointer goes out of scope, its destructor fires and frees the memory. Magic? No, RAII (Resource Acquisition Is Initialization) — one of the cornerstones of C++.

\n\n

Since C++11, smart pointers have become part of the standard library (<memory>). Forget about auto_ptr (it's deprecated and dangerous). Now we have three heroes:

\n\n
    \n
  • std::unique_ptr — the sole owner.
  • \n
  • std::shared_ptr — a resource with "collective ownership."
  • \n
  • std::weak_ptr — an "observer" that doesn't interfere with life.
  • \n
\n\n

Let's break down each one in simple terms and with code.

\n\n

std::unique_ptr: "It's Mine, and No One Else's!"

\n\n

std::unique_ptr is the simplest and fastest smart pointer. It guarantees that ownership of the object belongs to only one pointer. You cannot copy a unique_ptr, but you can move it (transfer ownership).

\n\n

When to use? Almost always when you create an object on the heap and know it will have a single owner throughout its lifetime.

\n\n

Example: Creation and Usage

\n\n
#include <iostream>\n#include <memory>  // for smart pointers\n\nclass Robot {\npublic:\n    Robot(const std::string& name) : name_(name) {\n        std::cout << "Robot " << name_ << " activated!\\n";\n    }\n    void speak() const { std::cout << name_ << ": Hello, world!\\n"; }\n    ~Robot() { std::cout << "Robot " << name_ << " destroyed.\\n"; }\nprivate:\n    std::string name_;\n};\n\nint main() {\n    // Creating a unique_ptr (never use new!)\n    std::unique_ptr<Robot> r1 = std::make_unique<Robot>("R2-D2");\n\n    r1->speak();  // Works like a regular pointer\n\n    // std::unique_ptr<Robot> r2 = r1; // Error! Cannot copy\n    std::unique_ptr<Robot> r2 = std::move(r1); // Move ownership\n\n    if (!r1) {\n        std::cout << "r1 is now empty, ownership transferred to r2\\n";\n    }\n\n    r2->speak();  // Works\n    // Here r2 goes out of scope and the robot is destroyed automatically\n    return 0;\n}
\n\n

Important: Use std::make_unique<T>(args...) instead of new

Blogs

Book Recommendations