Channels ▼
RSS

C/C++

Smart Pointers in Boost


Introducing Boost

According to the Boost website, Boost is "a repository of free, portable, peer-reviewed C++ libraries. Boost acts as a proving ground for new libraries, particularly those that work well with the ISO C++ Standard library." But Boost is more than a collection of libraries. It is also the focus of a rapidly growing community of developers who create, use, and discuss the Boost libraries. Beyond making these excellent libraries available, Boost also offers a place to learn. The libraries are examples of solid library design in a world that seldom seems to look further than the next release. Joining the discussions on the Boost mailing list (either actively or just by listening) is a good way to improve your understanding of library design problems and solutions. Boost also provides a rapidly growing Boost-Users mailing list that focuses on questions related to using the libraries.

The quality and the technological standard of the Boost libraries are amazing. And the Boost portability standard ensures that when you move your code to another platform, you'll know the libraries will still work. The current release, Boost 1.25.0, consists of libraries ranging from smart pointers to regular expressions to a portable threading library. Boost currently supports 35 libraries, all of which have been thoroughly reviewed by community members. These libraries can be freely used, and many of them are being used in commercial applications.

Boost is one of the strongest C++ communities. Among the 2,000 members are many of the world's top C++ programmers. Members stay involved because they like working with some of the best minds in programming. They also know their efforts are bound to have an impact on the C++ community, since much of what you see in Boost is a strong candidate for inclusion in the next C++ Standard.

The best way to get acquainted with Boost is to tour the Boost libraries. In this article, I'll introduce you to the Boost smart pointer library smart_ptr. smart_ptr is a good example of the innovation and sound design you'll find in Boost. I encourage you to visit the Boost website (www.boost.org) for more on the other 34 libraries in the Boost collection.

Smart Pointers

One of the smaller (size-wise) Boost libraries is smart_ptr. smart_ptr is one of the libraries that I think is going to end up in the C++ Standard. This article discusses the Boost smart_ptr library. But first, I'll begin with a brief introduction to smart pointers.

30-Second Introduction to Smart Pointers

Smart pointers are classes that store pointers to dynamically allocated (heap) objects. They behave much like built-in C++ pointers except that they automatically delete the object pointed to at the appropriate time. Smart pointers are particularly useful in the face of exceptions as they ensure proper destruction of dynamically allocated objects. They can also be used to keep track of dynamically allocated objects shared by multiple owners.

Actually, smart pointers can do more, such as handle thread safety, provide copy-on-write, ensure protocols, and provide remote communication services. There are ways to create generic smart pointers for these ESPs (Extremely Smart Pointers), but those won't be covered here. (See [1] for in-depth coverage of this topic. By the way, Alexandrescu is currently considering submitting his C++ library Loki to Boost.)

Most uses of smart pointers are for lifetime control, period. They implement operator-> and operator* to yield the raw pointer, allowing the smart pointer to look like an ordinary pointer.

One such class comes with the standard library: std::auto_ptr. It is designed to handle ownership of a resource, but lacks support for reference counting and arrays. Also, std::auto_ptr transfers ownership when it is copied. In many cases, you need more and/or different functionality. Enter the smart_ptr classes.

smart_ptr Classes

The smart pointers in Boost are:

  • scoped_ptr, which handles sole ownership of single objects; unlike std::auto_ptr, scoped_ptr cannot be copied
  • scoped_array, which is similar to scoped_ptr, but handles arrays
  • shared_ptr, which allows object ownership to be shared
  • shared_array, which allows sharing of ownership for arrays

scoped_ptr

The scoped_ptr smart pointer differs from std::auto_ptr in that it doesn't transfer ownership. In fact, it explicitly forbids any attempt to do so! This is important for any scenario where you need to be sure that there is only ever one owner to a pointer. Without scoped_ptr, you would probably be inclined to use std::auto_ptr, but take a look at the following code:

auto_ptr<string> MyOwnString
  (new string("This is mine to keep!"));
auto_ptr<string> NoItsMine(MyOwnString);

cout << *MyOwnString << endl; // Boom

This code will obviously fail, since ownership of the string has been transferred to NoItsMine. This is not a design flaw in std::auto_ptr — it is a feature. However, when you need MyOwnString to be just that, you'll want to use scoped_ptr:

scoped_ptr<string> MyOwnString
  (new string("This is mine to keep for real!"));
// Compiler error - there is no copy constructor.
scoped_ptr<string> TryingToTakeItAnyway
  (MyOwnString); 

The scoped_ptr accomplishes this behavior by inheriting from boost::noncopyable (found in the library Boost.utility). The non-copyable class declares the copy constructor and the assignment operator as private.

scoped_array

scoped_array is obviously the equivalent of scoped_ptr, but for arrays. You'll get no help from the standard library here — unless of course you're using std::vector, which is the right way to go in most cases.

The usage is similar to scoped_ptr:

>
typedef tuples::tuple<string, int> ArrayTuple;

scoped_array<ArrayTuple> MyArray(new ArrayTuple[10]);
tuples::get<0>(MyArray[5]) =
  "The library Tuples is also part of Boost";

Tuples are collections of elements — for example pairs, triples, and quadruples. A typical use of tuples is returning multiple values from a function. The Boost Tuple Library can be thought of as an extended generalization of the standard library's pair, and it currently works with up to 10 tuple elements. It supports tuple streaming, comparison, assignment, unpacking, and more. For more information about the Boost Tuple Library, see [3].

As the scoped_array goes out of scope, delete[] will be properly called. This eliminates a common mistake, namely invoking the wrong operator delete.

shared_ptr

Here's an offering that you won't find in the standard library — a reference-counted smart pointer. Most of you have rolled your own smart pointers, and there is plenty of literature regarding the issues involved in reference counting. One of the most important details is how the reference count is implemented — intrusive, which means that you add support to the classes being reference counted, or non-intrusive, which means you don't. The Boost shared_ptr is non-intrusive, and the implementation uses a reference counter allocated from the heap. There has been much discussion about providing parameterized strategies to best suit any given situation, but in the end it was decided against to focus on usability. Don't expect the discussions to go away though.

The usage of shared_ptr does what you'd expect: it takes responsibility of deleting the pointee when there are no more users of the instance, and it shares its pointee freely.

void PrintIfString(const any& Any) {
  if (const shared_ptr<string>* s =
    any_cast<shared_ptr<string> >(&Any)) {
      cout << **s << endl;
    }
}

int main(int argc, char* argv[])
{
  std::vector<boost::any> Stuff;

  shared_ptr<string> SharedString1
    (new string("Share me. By the way,
     Boost.any is another useful Boost
     library"));

  shared_ptr<string> SharedString2
    (SharedString1);
  shared_ptr<int> SharedInt1
    (new int(42));
  shared_ptr<int> SharedInt2
    (SharedInt1);

  Stuff.push_back(SharedString1);
  Stuff.push_back(SharedString2);
  Stuff.push_back(SharedInt1);
  Stuff.push_back(SharedInt2);

  // Print the strings
  for_each(Stuff.begin(), Stuff.end(),
    PrintIfString);

  Stuff.clear();

  // The pointees of the shared_ptr's
  // will be released on leaving scope
  return 0;
}

The any library offers a way to store just about anything [2] [4]. The requirements on contained types are that they are CopyConstructible, the destructor must not throw, and they should typically be Assignable. How do we store and pass "anything"? Indiscriminate types (read void*) can refer to just about anything, but that means throwing type safety (and knowledge) out the door. Using any, type safety is preserved. All types satisfying the requirements for any can be assigned, but extraction demands knowing the exact type. any_cast is the key for unlocking the value held by any. any_cast works like dynamic_cast — casts to pointer types succeed or fail by returning a null pointer whereas casts to reference types throw an exception (bad_any_cast) on failure.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video