Smart Pointers

  • auto_ptr

  • unique_ptr

  • shared_ptr

std::auto_ptr<T> (until C++17)

  • modeled class to manage dynamically allocated memory.

  • provides all the interfaces provided by normal pointers with a few

    exceptions.

  • during construction, it owns the memory and releases the same when it

    goes out of scope.

Simple example

#include <iostream>
#include <memory>
using std::auto_ptr, std::cout, std::endl;

class SomeClass{
public:
    SomeClass(int a = 0) : m_a(a) { }
    ~SomeClass() { cout << "Calling destructor" << m_a <<endl; }
public:
    int m_a;
};

int main(){
    auto_ptr<SomeClass> ptr(new SomeClass(5));
    cout << ptr->m_a << endl;
    return 0;
}

We didn't have to call delete to deallocate memory and call the destructor.

Solving memory leaks and exceptions

Now take a look at the following code:

This is the desired result.

Here coded the same but with a regular pointer

We see here that we didn't call delete ptr which causes a memory leak.

Now obviously we could have done some like this which would have solved our problems but still this may not be possible in every case or maybe more cumbersome

std::unique_ptr<T>

  • unique_ptr follows the exclusive ownership semantics, i.e., at any point of time, the resource is owned by only one unique_ptr.

  • When unique_ptr goes out of scope, the resource is released.

  • If the resource is overwritten by some other resource, the previously owned resource is released. So it guarantees that the associated resource is released always.

Example

std::move(uniqPtr) allows us to transfer ownership.

as stated before the following is not allowed

This is becaues unique_ptr copy ctor and copy assignment look like this

A sub-category is make_unique

Here we didn't use new as before like in uniqPtr(new SomeClass(100)) just the class name.

Differences between std::make_unique and std::unique_ptrarrow-up-right

std::shared_ptr<T>

  • Multiple shared pointers can refer to a single object

  • When the last shared pointer goes out of scope, memory is released automatically. This is known by reference counting.

Creation

if created with the syntax above the shared_ptrreleases the associated resource by calling delete by default

Custom deletion

If the user needs a different destruction policy, he/she is free to specify the same while constructing the shared_ptr.

Here we game a lambda expression to call delete[] instead

Member functions

  • get() : To get the resource associated with the shared_ptr.

  • reset(): To yield the ownership of the associated memory block. If this is the last shared_ptr owning the resource, then the resource is released automatically.

  • unique(): (until C++20) To know whether the resource is managed by only this shared_ptr instance.

  • use_count(): get number of shared resources

  • operator bool: To check whether the shared_ptr owns a memory block or not. Can be used with an if condition. if (ptr) {

Example 1

Here we see that the destructor is only called when the number of references goes down to 0. Also we notice that on line 22 which is } the ref count goes down 1.

Example 2

Notice how Calling destructor1 was called before. This is because of reset()

Note: if we were to do the following std::make_shared<SomeClass>( SomeClass(2)) we would see the dtor twice. See herearrow-up-right for more info

The difference is that std::make_shared performs one heap-allocation, whereas calling the std::shared_ptr constructor performs two.

std::shared_ptr manages two entities:

  • the control block (stores meta data such as ref-counts, type-erased deleter, etc)

  • the object being managed

std::make_shared performs a single heap-allocation accounting for the space necessary for both the control block and the data. Here also we don't use the new keyword just as make_unique

Difference in make_shared and normal shared_ptr in C++arrow-up-right

Function example

More examples

When sptr2 goes out of scope, p is already destroyed . Valgrind will warn us.

The following is okay

std::weak_ptr

Doesn't increment the reference count to a shared pointer

Cool polymorphic example

How easy was this we didn't have to deallocate the memory ourselves.

Last updated