SyntaxStudy
Sign Up
C++ unique_ptr: Exclusive Ownership
C++ Beginner 1 min read

unique_ptr: Exclusive Ownership

'std::unique_ptr' is a smart pointer that expresses exclusive ownership of a heap-allocated object. When the 'unique_ptr' is destroyed, it automatically deletes the managed object. Because ownership is exclusive, 'unique_ptr' cannot be copied — only moved. This prevents accidental double-free errors that arise when multiple raw pointers alias the same allocation. 'std::make_unique' is the preferred factory function for creating 'unique_ptr' objects. It constructs the managed object and wraps it in a single step, is exception-safe, and avoids repeating the type name. Using 'make_unique' rather than 'new' directly should be the default in all modern C++ code. 'unique_ptr' integrates seamlessly with polymorphism and containers. A 'std::vector>' stores polymorphic objects by pointer without manual memory management, and elements are automatically destroyed when the vector is destroyed or an element is erased. Custom deleters can be supplied as a second template argument for resources that require non-delete cleanup.
Example
#include <iostream>
#include <memory>
#include <vector>
#include <utility>   // std::move

struct Node {
    int value;
    std::unique_ptr<Node> next;

    explicit Node(int v) : value(v), next(nullptr) {
        std::cout << "Node(" << value << ") created\n";
    }
    ~Node() {
        std::cout << "Node(" << value << ") destroyed\n";
    }
};

class LinkedList {
public:
    void prepend(int val) {
        auto node = std::make_unique<Node>(val);
        node->next = std::move(head_);   // transfer ownership
        head_ = std::move(node);
    }

    void print() const {
        for (Node* n = head_.get(); n; n = n->next.get())
            std::cout << n->value << " -> ";
        std::cout << "null\n";
    }

private:
    std::unique_ptr<Node> head_;
};

// Factory returning unique_ptr
std::unique_ptr<std::string> makeGreeting(const std::string& name) {
    return std::make_unique<std::string>("Hello, " + name + "!");
}

int main() {
    {
        LinkedList list;
        list.prepend(3);
        list.prepend(2);
        list.prepend(1);
        list.print();
        // all nodes destroyed automatically at end of scope
    }
    std::cout << "List destroyed\n";

    auto msg = makeGreeting("unique_ptr");
    std::cout << *msg << "\n";

    // unique_ptr cannot be copied — only moved
    auto p1 = std::make_unique<int>(42);
    auto p2 = std::move(p1);   // p1 is now nullptr
    std::cout << "p2 = " << *p2 << "\n";
    std::cout << "p1 is " << (p1 ? "not null" : "null") << "\n";

    return 0;
}