Click here to Skip to main content
Click here to Skip to main content

Improving on shared_ptr

, 15 Jun 2012
Rate this:
Please Sign up or sign in to vote.
A more efficient way to create objects for usage with shared_ptr.

Creation of objects for using with std::shared_ptr 

In this post I will tell about an optimization I have recently discovered and successfully applied in my project. It is very simple to apply but yields very good results - in terms of both performance and memory footprint.

Let's start with the usual way shared_ptrs are created:

class Test  
{  
public:  
  Test(int dummy) {}  
}  
...  
  
std::shared_ptr<Test> pTest(new Test(1));

Now let's look step by step at what's going on here:

  1. A new object of class Test is allocated and constructed. Note that it is allocated on the heap, and each heap allocation incurs memory overhead above sizeof(Test). Allocation overheads are discussed in more detail in this blog post.
  2. Then a pointer is passed to the constructor of std::shared_ptr<Test> which takes ownership of the newly created object. 

The mentioned constructor of shared_ptr basically does two things: it assigns its internal pointer to the object that it will hold, and it allocates (again on the heap!) a shared buffer that will be used to hold reference counters. As you can see, here's another memory allocation, another performance and memory footprint hit. So the more efficient way of doing it is:

std::shared_ptr<Test> pTest = std::make_shared<Test>(1);

There are a few benefits of doing this:

  • There is only one memory allocation - both reference counters and the object itself are allocated in one buffer (however this is implementation-dependent, so this is the case for Visual C++ 10)
  • There is a constructor of std::shared_ptr<T> that takes an R-value reference as an argument, making this construct potentially more efficient

What are the drawbacks here you might ask? There are only a few of these:

  • As Visual C++ 10 (and beta of VC11) does not support variadic templates number of arguments passed to object's constructor is limited to 10 (and in VC11 to 5 with default settings)
  • std::make_shared's from the boost library does not support this optimization and even in the latest version available now (1.49.0) allocates two separate buffers - one for the object and one for reference counters

So anyway, if you have boost::shared_ptrs and you are using boost starting from 1.36.0 in your project (that's the version that make_shared was copied from tr1 to boost library), it might still make sense to migrate to make_shared even if you won't get the benefits right away.

Is it that simple?

No, there is one small pitfall I hit when I migrated my project to using std::make_shared. When the object is being created by some factory class, the constructor is declared private and the factory class is declared as a friend. The problem lies in the fact that when the factory creates a new object with make_shared the constructor is called from some unknown implementation-specific class, and this call fails to compile as we can't declare it a friend of our class. The solution is not very elegant (at least for my taste), but it works, and helps when this optimization is applied to make a real difference in performance. Here is a sample code:

class Obj;  
typedef std::shared_ptr ObjPtr;  
  
class Obj  
{  
  ...  
  private:  
  struct HideMe {}  
  friend class ObjFactory;  
public:  
  Obj(HideMe, int param)  
  { ... }  
}  
  
class ObjFactory  
{   
public:  
  static ObjPtr CreateObj()  
  {  
    return std::make_shared(Obj::HideMe(), param) ;  
  }  
}

So the actual constructor that is being called by ObjFactory is public, but no other object could invoke it due to the hidden structure Obj::HideMe.

Happy optimizing!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

AlexZakharenko

Ukraine Ukraine
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web04 | 2.8.140827.1 | Last Updated 15 Jun 2012
Article Copyright 2012 by AlexZakharenko
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid