Custom deleter for boost::shared_ptr

As a good introduction to some of the most interesting boost libraries you can read "Beyond the C++ Standard Library: An Introduction to Boost", by Björn Karlsson, an Addison Wesley Professional book. That's what I'm actually doing, and these are a few notes that I'm jotting down in the meanwhile.

The shared_ptr custom deleter is helpful for handling resources that need something more that calling a simple delete on the pointer.

As example, here we see how to manage a stdio FILE pointer via shared_ptr.

We define a functor, FileCloser, to perform the cleanup operation. Actually, if we were not interested in other than calling fclose(), we could avoid using the functor, and just passing the function to the shared_ptr constructor as custom deleter. Here we want some simple logging, to show how and when the deleter is called, so we do use the functor.

#include <iostream>
#include <cstdio>
#include "boost/shared_ptr.hpp"

using std::cout;
using std::endl;
using std::FILE;
using std::fclose;
using boost::shared_ptr;

namespace
{
class FileCloser
{
public:
void operator()(FILE* file)
{
cout << "FileCloser in action!" << endl;
if(file != 0)
fclose(file);
}
};
}

void filePtr() {
cout << "shared_ptr example with a custom deallocator" << endl;

{
FILE* f = fopen("smart04.cpp","r");
if(f == 0)
{
cout << "Unable to open file" << endl;
return;
}

shared_ptr<FILE> sharedFile(f, FileCloser());
fseek(sharedFile.get(), 42, SEEK_SET);
}
cout << "FILE closed by the shared_ptr custom deleter" << endl;
}

We could also use the custom deleter to implement a better security on the type.

Declaring the destructor as protected (or private) and use an inner functor as custom deleter will do the trick. In this case we declare the functor as private inner class, so, in order to call the shared_ptr constructor passing the functor as custom deleter, we have to define a public function of the class, otherwise there would be no access right to the functor.


#include <iostream>
#include "boost/shared_ptr.hpp"

using std::cout;
using std::endl;
using boost::shared_ptr;

namespace
{
class A
{
class ADeleter
{
public:
void operator()(A* p)
{
cout << "ADeleter in action" << endl;
delete p;
}
};

public:
virtual void sing()
{
cout << "Lalalalalalalalalalala" << endl;
}

static boost::shared_ptr<A> createA()
{
shared_ptr<A> p(new A(), A::ADeleter());
return p;
}

protected:
virtual ~A() {};
};
}

void safePtr()
{
shared_ptr<A> p = A::createA();
p->sing();

// A a; // do not compile: dtor protected
A* a = p.get();
a->sing();
// delete a; // do not compile: protected
}

No comments:

Post a Comment