BKStart a conversation ↗

C++11–shared_ptr

To be honest, it’s been a long time since I did any real C++, however I’ve been reading a Java book lately and it’s made me kinda lonesome for C++, the Java book goes into a lot of detail about core language structure, it’s not a book on hibernate, swing etc, just core fundamentals like differences between an internal private class or an internal private interface, static binding of fields etc. I remember when I was at the height of my C++ development career I knew the intricacies about default parameters being statically bound in polymorphic classes, I knew about private inheritance, pitfalls of overriding non virtual functions, thinking back I knew the language quite intimately. Sure in the .NET world I know quite a lot of the framework and the libraries toolsets etc (because I’m a greedy little pig and want to know everything) but, I wonder do I know the C# language quite as well as I once knew C++.

As I said at the outset I’ve been away from C++ for a few years now, I think the last time I did any commercial C++ was in 2006 when I was up to my eyeballs in boost/stl/wtl/atl etc, so what’s changed? Well there’s a new standard for one, C++11. Just to keep my finger in I’ve decided to start writing a few little blog posts on the new standard, this is the first one.

In Boost we used to use shared_ptr, this class template stored a pointer to a dynamically allocated object, the object pointed to was guaranteed to be deleted when the last shared_ptr pointing to it was destroyed or reset.

e.g.

#include <vector>
#include <set>
#include <iostream>
#include <algorithm>
#include <boost/shared_ptr.hpp>

//  The application will produce a series of
//  objects of type Foo which later must be
//  accessed both by occurrence (std::vector)
//  and by ordering relationship (std::set).

struct Foo
{
  Foo( int _x ) : x(_x) {}
  ~Foo() { std::cout << "Destructing a Foo with x=" << x << "\n"; }
  int x;
  /* ... */
};

typedef boost::shared_ptr<Foo> FooPtr;

struct FooPtrOps
{
  bool operator()( const FooPtr & a, const FooPtr & b )
    { return a->x > b->x; }
  void operator()( const FooPtr & a )
    { std::cout << a->x << "\n"; }
};

int main()
{
  std::vector<FooPtr>         foo_vector;
  std::set<FooPtr,FooPtrOps>  foo_set; // NOT multiset!

  FooPtr foo_ptr( new Foo( 2 ) );
  foo_vector.push_back( foo_ptr );
  foo_set.insert( foo_ptr );

  foo_ptr.reset( new Foo( 1 ) );
  foo_vector.push_back( foo_ptr );
  foo_set.insert( foo_ptr );

  foo_ptr.reset( new Foo( 3 ) );
  foo_vector.push_back( foo_ptr );
  foo_set.insert( foo_ptr );

  foo_ptr.reset ( new Foo( 2 ) );
  foo_vector.push_back( foo_ptr );
  foo_set.insert( foo_ptr );

  std::cout << "foo_vector:\n";
  std::for_each( foo_vector.begin(), foo_vector.end(), FooPtrOps() );

  std::cout << "\nfoo_set:\n";
  std::for_each( foo_set.begin(), foo_set.end(), FooPtrOps() );
  std::cout << "\n";

//  Expected output:
//
//   foo_vector:
//   2
//   1
//   3
//   2
//
//   foo_set:
//   3
//   2
//   1
//
//   Destructing a Foo with x=2
//   Destructing a Foo with x=1
//   Destructing a Foo with x=3
//   Destructing a Foo with x=2

  return 0;
}

In C++11 we now get a shared pointer as part of the standard, see my example below.

I know there were some overheads to the boost shared pointer, memory footprint etc, (consider 1x10^6 of these guys in a container!). But in general shared_ptr can help you, because if you do it manually you’ll likely write slower, buggier code (or both).