Avoid memory leak using shared_ptr

Shared_ptr was first designed and implemented in boost, and finally became part of the C++11 Standard as std::shared_ptr. Boost defines it as, “The shared_ptr class template stores a pointer to a dynamically allocated object, typically with a C++ new-expression. The object pointed to is guaranteed to be deleted when the last shared_ptr pointing to it is destroyed or reset.” This auto-delete character makes it possible to avoid memory leak.

It’s not hard to use shared_ptr. We just create an object, pass it to the shared_ptr, use the pointer as a common one, and have no need to care about when to delete it. Here is a simple example:

#include <iostream>
#include <memory>

class UserDefinedClass{
    int     GetValue();
    void    SetValue(const int value);

    int value_;

UserDefinedClass::UserDefinedClass() {
    value_ = 0;

int UserDefinedClass::GetValue() {
    return value_;

void UserDefinedClass::SetValue(const int value) {
    value_  =    value;

int main() {
    std::shared_ptr<UserDefinedClass> sp1;
    std::shared_ptr<UserDefinedClass> sp2(new UserDefinedClass);

    sp1 = sp2;

     if (sp1) std::cout << "sp1: " << sp1->GetValue() << '\n';
     if (sp2) std::cout << "sp2: " << sp2->GetValue() << '\n';

     return 0;

In the above code, we can eliminate the “new” operation by using “make_shared” to get an efficiency benefit by consolidating allocation.

When considering arrays, we can combined the vector with shared_ptr. The following example will show us how to do.

#include <cstdio>
#include <cstring>
#include <memory>
#include <thread>
#include <mutex>
#include <vector>
#include <semaphore.h>

using namespace std;

#define   MAX_CACHE_SIZE    100
#define   MAX_BUFFER_SIZE   (1024*1024)

struct MemoryUnit{
    int size;
    // there is a space between the two '>' characters
    shared_ptr<vector<char> > buffer;

struct MemoryCache{
    pthread_mutex_t  mutex_cache;
    sem_t    sem_empty;
    sem_t    sem_full;
    vector<struct MemoryUnit> cached_vector;

class SharedPtrDemo{
    void Start();

    struct MemoryCache  memory_cache;
    pthread_t  producer_thread_id;
    pthread_t  consumer_thread_id;
    void  Producer();
    void  Consumer();

    static void* ProducerEntrance(void* args)  {
        if (NULL == args) return NULL;

        SharedPtrDemo* instance = static_cast<SharedPtrDemo*>(args);
        if (instance)

        return NULL;

    static void* ConsumerEntrance(void* args) {
        if (NULL == args) return NULL;

        SharedPtrDemo* instance = static_cast<SharedPtrDemo*>(args);
        if (instance)

        return NULL;

SharedPtrDemo::SharedPtrDemo() {
    pthread_mutex_init(&memory_cache.mutex_cache, NULL);
    sem_init(&memory_cache.sem_empty, 0, MAX_CACHE_SIZE);
    sem_init(&memory_cache.sem_full, 0, 0);

SharedPtrDemo::~SharedPtrDemo() {

void SharedPtrDemo::Start() {
                   (SharedPtrDemo* )this);

                   (SharedPtrDemo* )this);

void SharedPtrDemo::Producer() {
    unsigned int  produced_count = 0;

    while(1) {
        struct MemoryUnit produced_unit;
        memset(&produced_unit, 0x00, sizeof(produced_unit));

        int memory_size = rand() % MAX_BUFFER_SIZE + 1;
        produced_unit.buffer = make_shared<vector<char> >(memory_size);

        // put whatever you want to the buffer
        memcpy(&(*produced_unit.buffer)[0], &produced_count,sizeof(produced_count));
        produced_unit.size =  memory_size;


void SharedPtrDemo:: Consumer() {
    int passed_value = 0;
    unsigned int consumed_count = 0;

    while(1) {
        struct MemoryUnit consumed_unit;
        memset(&consumed_unit, 0x00, sizeof(consumed_unit));

        vector<struct MemoryUnit>::iterator vector_it
            = memory_cache.cached_vector.begin();
        consumed_unit = *vector_it;

        // use the buffer, then it will be destroyed automatically
        memcpy(&passed_value, &(*consumed_unit.buffer)[0], sizeof(passed_value));
        printf("Consumed %d units, and the value = %d\n",
               ++consumed_count, passed_value);

int main() {
    SharedPtrDemo demo;


    return 0;

Convenient as it is, there are some potential dangers when using shared_ptr.

1)Avoid the circular references

Because the implementation of shared_ptr uses reference counting, while circular references will make the mechanism fail. Here is an example:

#include <memory>
#include <iostream>

using namespace std;

class B;
class A{
    shared_ptr<B> b_ptr;
    A() {cout << "A() \n";}
    ~A() {cout << "~A() \n";}

class B{
    shared_ptr<A> a_ptr;  // use weak_ptr to break the cycle
    B() {cout << "B() \n";}
    ~B() {cout << "~B() \n";}

int main() {
    shared_ptr<A> a_ = make_shared<A>();
    shared_ptr<B> b_ = make_shared<B>();
    a_->b_ptr = b_;
    b_->a_ptr = a_;

    return 0;

This program will end up with print “A()” and “B()”. There’s no destruction of A and B. There will surely lead to memory leak, and make a long-lived program be killed eventually. To break the cycle, we can use weak_ptr.

2)Always use make_shared instead of new

Make_shared will help us to achieve high performance and avoid memory leak in some situation. For example, code like F(std::shared_ptr<T>(new T), g()) might cause a memory leak if g throws an exception because g() may be called after new T and before the constructor of shared_ptr<T>. While this doesn’t occur in F(std::make_shared<T>(), g()), since two function calls are never interleaved.

3) Avoid to use the raw pointer

Calling the get() function to get the raw pointer or passing a reference of a raw pointer to a shared_ptr would be dangerous, because the internal count won’t increase.

As we’ve learned the memory fragmentation problem before. Will there be the same problem with shared_ptr? Well, we can see that shared_ptr uses new to allocate memory on the heap. And some memory usage patterns, those with many long-lived small objects, are trend to cause memory fragmentation. And we can use third party memory libraries such as jemalloc and tcmalloc to avoid it.


1)Official definition of shared_ptr class template


2)Potential dangers when using boost::shared_ptr


3)Why should we almost always use make_shared

GotW #89 Solution: Smart Pointers

4)Performance compared with make_shared and new


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s