Smart Pointers

If you know a bit of C++ coding, you are forcely aware of the pitfalls you may encur while using pointers. However such an abstract data type is mostly used via its smart versions. Smart pointers are abstractions that aids the developer to overcome issues of memory allocation, leak and loosen relationship between what the execution program has in memory and what the executed code it is capable of handling. This small post is aimed to list and summarize the different smart pointers that can be used in C++ and give a little of background on how to use them and why. The examples are taken from the web.

std::auto_ptr

Description: it is part of the C++ Standard Library, it stores a pointer to single allocated objects. It means that whenever the pointer is referenced by a second auto_ptr it loses the ownership: sauto_ptr have strict ownership, it means that only the last assigned scoped_ptr really contains the address of the object. Look at the example for clarifications. Strict ownership is useful while you want to ensure to really knows that the pointer you are handling is the only one that can destroy the object and it cannot be done by someone else.

Benefits: This pointer is useful whenever you need to allocate local variables that you never want to have accessible outside of the scope.

Example:

#include <iostream>
#include <memory>

int main(int argc, char **argv)
{
 int *i = new int;
 std::auto_ptr<int> first(i);
 std::auto_ptr<int> second;

 second = first;

 std::cout << first.get() << std::endl;  // NULL
 std::cout << second.get() << std::endl; // Good address

 return 0;
}

boost::scoped_ptr

Description: it is part of boost.org C++ Library. Peculiariy of scoped_ptr is that it guarantees the object to be deleted. You can delete it either via destructor or by calling reset function. Once the definition of the pointer exits the execution scope, the destructor is automatically called and it deallocate the memory taken by the scoped_ptr.

Benefits: scoped_ptr adds an extra guarantee that all dynamic allocate memory areas will be deallocated when the execution is out of scope, even if the destructor for the given type is never called (or forgotten). Like the auto_ptr it does not have extra attributed definite with it, therefore it has no memory overhead (i.e. no extra storage required compared to a classic pointer).

Example:

#include <boost/scoped_ptr.hpp>
#include <iostream>

struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };

class MyClass {
 boost::scoped_ptr<int> ptr;
 public:
 MyClass() : ptr(new int) { *ptr = 0; }
 int add_one() { return ++*ptr; }
};

int main()
{
 boost::scoped_ptr<Shoe> x(new Shoe);
 MyClass my_instance;
 std::cout << my_instance.add_one() << '\n';
 std::cout << my_instance.add_one() << '\n';
}

boost::shared_ptr

Description: The shared_ptr is an enhanced version of scoped_ptr. It guarantees that the memory allocated will be finally deleted after the last instance of shared_ptr to that memory index is reset or destroyed. It is part of the boost.org C++ Library and it is using reference counting to detect when the destructor needs to be called (also called shared ownership principle).

Benefits: It takes care of deallocating the memory when the very last reference to that pointer is used. It could be very helpful in distributed environments since it can be used to reference the same object concurrently by different Thread “safely”.

Example:

shared_ptr<A> a(new A);
shared_ptr<A> b(a);

// Thread 1     // Thread 2
 a.reset();      b.reset();

boost::weak_ptr

Description: It is a smart pointer that holds a non-owning reference to an object that is already maanged by a shared_ptr. Since its relationship is “weak”, it does not increase the reference counter of shared_ptr. It is again part of the boost.org C++ Library.

Benefits: It is useful whenever you do not need to add a new reference that change the last ownership of the pointer. It can also be used to solve tricky issues with cyclic references.

Example:

std::shared_ptr<int> p1(new int(5));
std::weak_ptr<int> wp1 = p1; //p1 owns the memory.

boost::intrusive_ptr

Description: it is a smart pointer that enables embedded reference count. It means you can redefine functions that are adding references and releasing them. They have really specific uses, therefore it is generally adsivsable to use shared_ptr pointers.

Benefits: Gives you more control on the refering system of smart pointer whereas in the meanwhile does not had any overhead in memory to the pointer itself.

Example:

#include <boost/intrusive_ptr.hpp>
#include <boost/atomic.hpp>

class X {
public:
 typedef boost::intrusive_ptr<X> pointer;
 X() : refcount_(0) {}

private:
 mutable boost::atomic<int> refcount_;
 friend void intrusive_ptr_add_ref(const X * x)
 {
 x->refcount_.fetch_add(1, boost::memory_order_relaxed);
 }
 friend void intrusive_ptr_release(const X * x)
 {
 if (x->refcount_.fetch_sub(1, boost::memory_order_release) == 1) {
 boost::atomic_thread_fence(boost::memory_order_acquire);
 delete x;
 }
 }
};

std::unique_ptr

Description: This last smart pointer is the most restrictive smart pointer: not only it handles the ownership of the allocated memory but it does not allow any other smart pointer to reference to the same address. as scoped_ptr it destroys the object when out of scope. It replaces the old auto_ptr in std library.

Benefits: it avoids uncertain ownership among scoped_ptr pointers.

Example:

void foo()
{
 std::unique_ptr<int> p(new int);
 //do some stuff that might throw
}

Comments

Leave a Reply