# Smart Pointer in C++ 2023

* **unique\_ptr:** Represents exclusive ownership of a resource. The resource is destroyed when the unique\_ptr goes out of scope.
* **shared\_ptr:** Represents shared ownership of a resource. The resource is destroyed when the last shared\_ptr goes out of scope.
* **weak\_ptr:** Represents a "weak" reference to a resource managed by a shared\_ptr. A weak\_ptr does not prolong the lifetime of the resource.

## unique\_ptr:

* Stores a unique pointer to an object
* Object is deleted when unique\_ptr goes out of scope or is reset()
* Example:

```cpp
std::unique_ptr<int> uptr = std::make_unique<int>(10);
int * raw = uptr.get();  // Get raw pointer
uptr.reset();  // Delete object
```

* Methods: get(), reset(), release(), operator->(), operator\*()

## shared\_ptr:

* Stores a shared pointer to an object
* Object is deleted when all shared\_ptrs are destroyed or reset
* Example:

```cpp
std::shared_ptr<int> sptr1 = std::make_shared<int>(10);
std::shared_ptr<int> sptr2 = sptr1;

sptr1.reset();  // sptr2 is still valid
sptr2.reset();  // Object deleted 
```

* Methods: get(), reset(), use\_count(), operator->(), operator\*()

## weak\_ptr:

* Stores a weak pointer to an object managed by shared\_ptr
* Does not increase the object's reference count
* Example:

```cpp
std::shared_ptr<int> sptr = std::make_shared<int>(10);
std::weak_ptr<int> wptr = sptr;

if (std::shared_ptr<int> ptr = wptr.lock()) { 
   // Use ptr 
}
```

* Methods: lock(), expired()

Hope this overview of the main smart pointer types in C++ is helpful!

## All the methods of smart pointer&#x20;

Here are the main methods for each smart pointer type in C++:

### unique\_ptr:

* get() - Returns the underlying raw pointer
* reset() - Resets the unique pointer, deletes the object
* release() - Releases ownership of the object, returns the raw pointer
* operator->() - Overloaded dereference operator
* operator\*() - Overloaded dereference operator

### shared\_ptr:

* get() - Returns the underlying raw pointer
* reset() - Resets the shared pointer, may delete the object if no other shared pointers exist
* use\_count() - Returns the number of shared pointers referring to the object
* operator->() - Overloaded dereference operator
* operator\*() - Overloaded dereference operator

### weak\_ptr:

* lock() - Attempts to lock the weak pointer, returning a shared pointer if the object still exists
* expired() - Checks if the object managed by the weak pointer still exists

Some other common methods:

* make\_unique() - Creates a unique pointer
* make\_shared() - Creates a shared pointer
* static\_pointer\_cast() - Casts between different pointer types
* dynamic\_pointer\_cast() - Uses RTTI to cast between different pointer types
* const\_pointer\_cast() - Casts away constness
* alias() - Creates an alias shared pointer (shares ownership)

Hope this overview of the main methods for each smart pointer type in C++ is helpful!

## get()

### get() for unique\_ptr:

```cpp
// Declare unique_ptr    
std::unique_ptr<int> up = std::make_unique<int>(10);

// Get raw pointer  
int* x = up.get();

// Use raw pointer   
std::cout << *x;  // Prints 10
```

### get() for shared\_ptr:

```cpp
// Declare shared_ptr
std::shared_ptr<int> sp = std::make_shared<int>(10);

// Get raw pointer
int* y = sp.get();

// Use raw pointer
std::cout << *y; // Prints 10
```

The get() method allows you to access the underlying raw pointer stored by the smart pointer.\
You can then dereference that pointer to access the object.

Keep in mind that after calling get(), the smart pointer still owns the object and will delete it when it goes out of scope.\
The raw pointer returned by get() is only valid as long as the smart pointer exists.

The get() method provides a way to interoperate with code that uses raw pointers.

Hope this helps explain get()! Let me know if you have any other questions.

## reset()&#x20;

### Calling reset() on a unique\_ptr will:

```cpp
// Declare unique_ptr    
std::unique_ptr<int> up = std::make_unique<int>(10);

// Reset the unique pointer  
up.reset();  

// up no longer owns the memory   
int* x = up.get();  // x is a dangling pointer!
```

* Delete the object it was pointing to (using delete)
* Release ownership of that memory
* Make the unique\_ptr empty (no longer owning any memory)

This essentially "resets" the unique pointer, allowing you to call make\_unique() again to allocate new memory.

### For shared\_ptr:

```cpp
std::shared_ptr<int> sp = std::make_shared<int>(10);

sp.reset();  
```

### Calling reset() on a shared\_ptr will:

* Decrement the reference count
* If the reference count reaches 0, the object will be deleted
* Makes the shared\_ptr empty, no longer owning any memory

So reset() allows you to essentially "reuse" the shared\_ptr for a new allocation.

Hope this helps explain reset()! Let me know if you have any other questions.

## release()

### For unique\_ptr:

```cpp
std::unique_ptr<int> up = std::make_unique<int>(10);

int* raw = up.release();

// up is now empty!
assert(up.get() == nullptr);

// raw owns the memory  
std::cout << *raw; // Prints 10

delete raw;  // Manually delete memory
```

`up.release()` will:

* Return the raw pointer owned by the unique\_ptr
* Release ownership of that memory
* Leave the unique\_ptr empty (no longer owning any memory)

This gives you the raw pointer so you can manually manage the memory. You are then responsible for deleting it.

### For shared\_ptr:

`shared_ptr` does not have a `release()` method since it uses reference counting.

Hope this helps explain `release()`! Let me know if you have any other questions.

## use\_count()

use\_count() for shared\_ptr will return the number of shared\_ptr objects that are managing the same memory.

For example:

```cpp
std::shared_ptr<int> p1 = std::make_shared<int>(5);
std::shared_ptr<int> p2 = p1;
std::shared_ptr<int> p3 = p1;

std::cout << p1.use_count(); // Prints 3

p2.reset(); 

std::cout << p1.use_count(); // Prints 2
```

Here:

* `p1`, `p2` and `p3` all point to the same memory allocation
* `use_count()` initially returns 3, as 3 shared pointers are managing that memory
* When `p2` is reset(), the count decrements to 2

`use_count()` allows you to determine how many shared pointers are currently managing an allocation. When the count reaches 0, the memory will be deallocated.

`use_count()` is only available for `shared_ptr` since it uses reference counting.

Hope this helps explain `use_count()`! Let me know if you have any other questions.

## lock()

### For weak\_ptr:

```
std::shared_ptr<int> p = std::make_shared<int>(5);

std::weak_ptr<int> wp = p;

// Check if memory still allocated
if(auto sp = wp.lock()) {
   std::cout << *sp; // Prints 5
} 
```

`wp.lock()` will:

* Attempt to "lock" the weak pointer by converting it to a shared pointer
* Only succeeds if the memory is still allocated (the shared\_ptr count is > 0)
* Returns an empty shared\_ptr if the memory has been deallocated

This allows you to check if the memory referenced by the weak pointer still exists, by locking it into a shared pointer.

`lock()` returns a shared pointer (scoped into `sp` in the example). You can then use that shared pointer to access the memory.

`lock()` is only available for `weak_ptr` since it does not own the memory itself.

Hope this helps explain `lock()`! Let me know if you have any other questions.

## expired()

### For weak\_ptr:

```
std::shared_ptr<int> p = std::make_shared<int>(5);

std::weak_ptr<int> wp = p;

// Check if memory has been deallocated 
if (wp.expired()) {
  std::cout << "Memory has expired!";
}
```

`expired()` will simply return true if the memory referenced by the weak pointer has been deallocated. It will return false if the memory is still alive.

You can use `expired()` to check if a weak pointer is still valid before attempting to `lock()` it.

For example:

```
if (!wp.expired()) {
  // Memory still alive, try to lock weak pointer  
  std::shared_ptr<int> sp = wp.lock();
}
```

`expired()` is only available for `weak_ptr` since it does not own the memory itself. It must check the state of the corresponding `shared_ptr`.

Hope this helps explain `expired()`! Let me know if you have any other questions.

## operator->()  or operator\*()  - Overloaded dereference operator

The operator->() and operator\*() methods are overloaded dereference operators for smart pointers. They allow you to access members and dereference the smart pointer similar to a raw pointer.

For example, with a unique\_ptr:

```cpp
std::unique_ptr<Foo> up = std::make_unique<Foo>();

up->someMethod();   // Call method using operator->

(*up).someMethod(); // Call method using operator*
```

Here we are able to call a method on the Foo object using either:

* operator->() , which lets us use the -> access operator
* operator\*(), which lets us dereference the pointer using \*

This allows smart pointers to be used in a similar way to raw pointers.

The overloaded dereference operators are implemented for:

* unique\_ptr
* shared\_ptr
* weak\_ptr

So in summary, operator->() and operator\*() allow smart pointers to be used similarly to raw pointers, by overloading the pointer dereference syntax.

Hope this explanation helps! Let me know if you have any other questions regarding smart pointers.

## make\_unique() - Creates a unique pointer

make\_unique() allows you to easily create a unique\_ptr with one call, rather than manually allocating memory and constructing a unique\_ptr.

For example:

```cpp
std::unique_ptr<Foo> up = std::make_unique<Foo>(10); 
```

Here `std::make_unique<Foo>(10)` will:

* Dynamically allocate memory for a Foo object
* Call the Foo constructor with the value 10
* Construct a unique\_ptr managing that memory

All in one call.

Compared to:

```cpp
Foo* raw = new Foo(10);
std::unique_ptr<Foo> up(raw);
```

make\_unique() provides a cleaner syntax to create unique pointers.

It takes a template argument for the pointer type, and arguments to forward to the object's constructor.

Hope this helps explain make\_unique()! Let me know if you have any other questions.

## make\_shared() - Creates a shared pointer

make\_shared() works similarly to make\_unique() but for shared\_ptr instead.

It allows you to create a shared\_ptr in one call, rather than manually allocating memory and constructing the shared\_ptr.

For example:

```cpp
std::shared_ptr<Foo> sp = std::make_shared<Foo>(10);
```

This will:

* Dynamically allocate memory for a Foo object
* Call the Foo constructor with 10
* Construct a shared\_ptr managing that memory

All in one call.

Compared to:

```cpp
Foo* raw = new Foo(10);  
std::shared_ptr<Foo> sp(raw);
```

make\_shared() is generally preferred over manually allocating memory and constructing the shared\_ptr because:

* It allows the memory allocation and shared\_ptr construction to be atomic
* It may allocate the reference counter block alongside the object, reducing memory usage

Hope this helps explain make\_shared()! Let me know if you have any other questions.

## static\_pointer\_cast() - Casts between different pointer types

static\_pointer\_cast allows you to cast between different pointer types, similar to a static\_cast.

For example:

```cpp
class Base {};
class Derived: public Base {};

std::unique_ptr<Base> base = std::make_unique<Derived>();

std::unique_ptr<Derived> derived = 
    std::static_pointer_cast<Derived>(base);
```

Here we:

* Create a unique\_ptr to a Base class
* It actually points to a Derived object
* We cast it to a unique\_ptr to Derived using static\_pointer\_cast

This performs a safe downcast from Base to Derived, since we know the actual type is Derived.

static\_pointer\_cast uses the compile time type information to perform the cast. It is similar to a static\_cast.

Advantages over a dynamic\_pointer\_cast :

* Faster - No RTTI is used
* Safer - Compiler can check the cast is valid

static\_pointer\_cast allows you to cast between compatible smart pointer types where you know the actual type at compile time.

Hope this helps explain static\_pointer\_cast! Let me know if you have any other questions.

## dynamic\_pointer\_cast() - Uses RTTI to cast between different pointer types

dynamic\_pointer\_cast uses RTTI (run-time type information) to perform a cast between compatible smart pointer types.

For example:

```cpp
class Base {};
class Derived: public Base {};

std::unique_ptr<Base> base = std::make_unique<Derived>();

std::unique_ptr<Derived> derived =
    std::dynamic_pointer_cast<Derived>(base);
```

Here we:

* Create a unique\_ptr to a Base class
* It actually points to a Derived object
* We cast it to a unique\_ptr to Derived using dynamic\_pointer\_cast

This performs a downcast from Base to Derived, using RTTI to determine the actual object type at run-time.

Advantages over static\_pointer\_cast:

* Can cast to pointers of unrelated types, as long as a conversion exists
* Will return a null pointer if the cast is not possible

dynamic\_pointer\_cast uses RTTI to determine if a cast is possible, and performs it at run-time.

It allows you to cast between smart pointer types when you don't know the exact types at compile time.

Hope this helps explain dynamic\_pointer\_cast! Let me know if you have any other questions.

## const\_pointer\_cast() - Casts away constness

const\_pointer\_cast allows you to cast away the const qualifier from a smart pointer, effectively casting away constness.

For example:

```cpp
std::shared_ptr<const int> cptr = std::make_shared<const int>(5);

std::shared_ptr<int> ptr = 
    std::const_pointer_cast<int>(cptr);

*ptr = 10;  // Ok, we cast away const 
```

Here we:

* Create a shared pointer to a const int
* Cast it to a shared pointer to a non-const int using const\_pointer\_cast
* We are then able to modify the value, since we cast away const

const\_pointer\_cast effectively performs a const\_cast on the underlying pointer.

It should be used with caution, as casting away constness can easily lead to undefined behavior.

const\_pointer\_cast allows you to cast smart pointers while casting away the const qualifier, but it is not recommended in most cases. Prefer avoiding the need for such casts where possible.

Hope this helps explain const\_pointer\_cast! Let me know if you have any other questions.

## alias() - Creates an alias shared pointer (shares ownership) explain one by one

alias() for shared\_ptr allows you to create an alias shared pointer that refers to the same object and shares ownership.

For example:

```cpp
std::shared_ptr<int> p1 = std::make_shared<int>(5);

std::shared_ptr<int> p2 = p1.alias();
```

Here:

* We create a shared pointer `p1` pointing to an integer
* We call `alias()` on `p1` to create an alias shared pointer `p2`

After this, both `p1` and `p2`:

* Point to the same integer object
* Share ownership of that object
* Have the same reference count

When either `p1` or `p2` is destroyed or reset, the other will still be valid since they share ownership.

`alias()` allows you to easily create a second shared pointer that refers to the same object, without copying the reference count.

The new alias shared pointer's reference count is tied to the original shared pointer.

Hope this helps explain alias()! Let me know if you have any other questions.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://adeshsingh.gitbook.io/programming/smart-pointer-in-c++-2023.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
