custom delete shared_ptr

Reading Time: 2 minutes

You might’ve used std::shared_ptr or std::unique_ptr earlier or at least might have heard about them. So what are these let’s have a look

The idea is to free up the programmer from explicitly freeing up a pointer when they’re done with it. So there are two most common type of smart pointers which manage themselves.

In C we’re used to call malloc or calloc when the memory is required dynamically and then free it up using free however what if the pointer is actually being used in multiple code path? How do we know that it’s safe to free the pointer? To answer these questions we can use either one of

std::shared_ptr or std::unique_ptr which manage themselves and automatically free up the underlying pointer they’re managing.

Initializing smart pointer

If you want the pointer to be held only by one entity you’ll want to use std::unique_ptr and if you want this to be shared among multiple code paths, you can use std::shared_ptr. Next let’s take a look how we can create both these

#include<memory>

int main(int argc, char *argv[]) {
    
    auto unique = std::make_unique<int>();
    auto shared = std::make_shared<long>();
} 

In the code shown to the left, we’ve created to smart pointers using std::make_unique and std::make_shared , which are templated so you can create any type of managed pointer.

The default allocation method is by using new this it’s guaranteed to call constructors of your class. Similarly the default method for freeing up this memory is delete and for arrays it’s delete [] .

Custom Deletors

What if we wanted to use a custom delete instead of freeing up memory using delete. Why would that be the case you might ask, now let’s take an practical example

Suppose you want to read a file and you would like to use stdio’s FILE and it’s methods to read / write file. Now we know that the FILE* returned is not from new and we need to free it up using fclose rather than delete . We’re going to use a custom delete function while we’ll create the pointer using fopen.

#include <cstdio>
#include <memory>

//This function is created so we can see
//the message being printed when the file is closed.
//static since we want this function to be private.
static void freeFilePointer(FILE *fptr)
{
        std::cout<<"Calling fclose\n";
        if (fptr != nullptr)
                ::fclose(fptr);
}

int main(int argc, char *argv[]) {
        FILE *fptr = fopen(fname, "r");
        auto file_ptr = std::shared_ptr<FILE>(fptr, freeFilePointer);
        return 0;
}

 

If you see the above code, we’ve not used make_shared but instead used a constructor form. This constructor requires that you provide a raw pointer and the way to delete it (second argument).

We’ve provided it our own function so we can see the cout message being printed otherwise you can directly use fclose. So what’s fancy about this?

Well we’ve already put in place the mechanism to free the resource when we created the resource. Thus anyone using this shared_ptr doesn’t need to worry about closing and freeing up the file pointer.

Leave a Reply