auto_ptr vs unique_ptr vs shared_ptr vs weak_ptr in C++

Last Updated : 19 Jan, 2026

A smart pointer is a stack-allocated object that wraps a raw pointer and automatically manages the lifetime of dynamically allocated memory.Smart pointers are provided by the C++ Standard Library in the <memory> header and help prevent:

  • Memory leaks
  • Dangling pointers
  • Double deletion

Types of Smart Pointers

  • std::auto_ptr (deprecated)
  • std::unique_ptr
  • std::shared_ptr
  • std::weak_ptr

They all are declared in a memory header file( #include<memory>) which is used to manage dynamic memory allocation.

1. auto_ptr (Deprecated)

auto_ptr was the first smart pointer introduced in C++. It manages a dynamically allocated object and deletes it when the auto_ptr goes out of scope.

Key Characteristics

  • Exclusive ownership
  • Ownership is transferred on copy
  • Source pointer becomes NULL
  • Unsafe copy semantics

Note: Deprecated in C++11 and removed in C++17

Auto pointer in C++

Example: 

C++
#include <iostream>
#include <memory>
using namespace std;

class A {
public:
    void show() { cout << "A::show()" << endl; }
};

int main() {
    auto_ptr<A> p1(new A);
    p1->show();

    cout << p1.get() << endl;

    auto_ptr<A> p2(p1); // ownership transferred
    p2->show();

    cout << p1.get() << endl; // p1 is now empty
    cout << p2.get() << endl;

    return 0;
}

Output:

A::show()
0x1b42c20
A::show()
0          
0x1b42c20

Explanation:

  • Copying p1 to p2 moves ownership, leaving p1 null.
  • This behavior breaks STL container requirements.

Why auto_ptr is Deprecated

  • Violates normal copy semantics
  • Cannot be used safely with STL containers
  • Leads to subtle bugs due to silent ownership transfer

2. unique_ptr

unique_ptr was introduced in C++11 as a safe replacement for auto_ptr.

Key Characteristics

  • Exclusive ownership
  • Cannot be copied
  • Ownership can be transferred using std::move()
  • Lightweight and efficient
  • Supports custom deleters and arrays

Invalid Copy (Compile-Time Error):

unique_ptr<A> p1(new A);
unique_ptr<A> p2 = p1; // ERROR

But, unique_ptr can be moved using the new move semantics i.e. using the std::move() function to transfer ownership of the contained pointer to another unique_ptr.

unique_ptr<A> p2 = move(p1); // Ownership transferred

So, it’s best to use unique_ptr when we want a single pointer to an object that will be reclaimed when that single pointer is destroyed. 

Example:

C++
#include <iostream>
#include <memory>
using namespace std;

class A {
public:
    void show() { cout << "A::show()" << endl; }
};

int main() {
    unique_ptr<A> p1(new A);
    p1->show();
    cout << p1.get() << endl;

    unique_ptr<A> p2 = move(p1);
    p2->show();

    cout << p1.get() << endl;
    cout << p2.get() << endl;

    return 0;
}

Output
A::show()
0x332feb0
A::show()
0
0x332feb0

When to Use unique_ptr

  • When only one owner should exist
  • Default choice for resource management
  • Best replacement for raw pointers

3. shared_ptr

shared_ptr implements shared ownership using reference counting.

Key Characteristics:

  • Multiple pointers can own the same object
  • Object is destroyed when reference count becomes zero
  • Slight overhead due to reference counting

Reference Counting:

  • use_count() returns number of active owners
  • Incremented on copy
  • Decremented on destruction/reset

Example:

C++
#include <iostream>
#include <memory>
using namespace std;

class A {
public:
    void show() { cout << "A::show()" << endl; }
};

int main() {
    shared_ptr<A> p1(new A);
    p1->show();

    shared_ptr<A> p2 = p1;
    p2->show();

    cout << p1.use_count() << endl;
    cout << p2.use_count() << endl;

    p1.reset();
    cout << p2.use_count() << endl;

    return 0;
}

Output
A::show()
A::show()
2
2
1

When to Use shared_ptr

  • When multiple owners must share a resource
  • Ownership lifetime is not clearly hierarchical

4. weak_ptr

weak_ptr is a non-owning reference to an object managed by shared_ptr.

Key Characteristics

  • Does not increase reference count
  • Prevents circular dependency
  • Must be converted using lock() before use

Problem: Circular Dependency with shared_ptr

If two objects hold shared_ptr to each other:

  • Reference count never reaches zero
  • Memory leak occurs                   Circular reference for weak pointer 

This is the reason we use weak pointers(weak_ptr) as they are not reference counted. So, the class in which weak_ptr is declared doesn’t have a stronghold over it i.e. the ownership isn’t shared, but they can have access to these objects. Circular reference for weak pointer 

So, in the case of shared_ptr because of cyclic dependency use_count never reaches zero which is prevented by using weak_ptr, which removes this problem by declaring A_ptr as weak_ptr, thus class A does not own it, only has access to it and we also need to check the validity of object as it may go out of scope. In general, it is a design issue.

Example:

C++
#include <iostream>
#include <memory>
using namespace std;

class A {
public:
    void show() { cout << "A::show()" << endl; }
};

int main() {
    shared_ptr<A> p1(new A);
    weak_ptr<A> wp = p1;

    cout << wp.use_count() << endl; // does not increment count

    if (auto sp = wp.lock()) {
        sp->show();
    }

    return 0;
}

Output
1
A::show()

When to Use weak_ptr

  • To break cyclic references
  • When you want access without ownership
  • Observer-like relationships
Comment