Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Who's the Smartest of 'Em All? Get to Know std::unique_ptr-3 : Page 3

C++0x now offers a safer and extremely versatile smart pointer class called std::unique_ptr. Learn how to implement strict ownership semantics with unique_ptr and benefit from its diverse services—customized deleters, safe usage with containers and algorithms, and array handling.


The Sink and Source Idiom
A source is a function that acquires a resource and passes the ownership of that resource to another function called a sink. A sink uses the resource and when it's done, it disposes of that resource. You can return unique_ptrby value from a source:

unique_ptr<int> source(int i)
 return unique_ptr<int>(new int(i));

void sink(unique_ptr<int>);
sink(source(5));//OK, implicit move from rvalue

Again, when moving from an lvalue you must use move()explicitly:

unique_ptr<int> up=source(5);
sink(up); //compilation error, implicit move from lvalue
sink(move(up)); //OK

To generalize, an implicit move from an rvalue unique_ptr is always safe and therefore may use copy syntax. Moving from an lvalue unique_ptr requires an explicit move()call.

Customizable Deleters
A deleter is a function that the smart pointer uses for deallocating its resource. By default, unique_ptr's deleter uses plain delete, as expected. However, certain resources require special cleanup operations. Here's how you install a custom deleter that has no effect:

struct nop_deleter
 template <class T> void operator()(T*) {}; // do nothing

int main()
 int n=0;
 // stack memory. Safe, deleter does nothing
unique_ptr<int, nop_deleter> pi(&n);
 *pi = 10;
 assert(sizeof(pi)==sizeof(int*)); //zero space overhead

In the following example, a custom deleter calls std::free() to deallocate an object allocated using std::malloc():

#include <cstdlib>
double* d =(double*) std::malloc(sizeof(double));
//deleter calls free(), not delete 
unique_ptr<int, void (*)(void*)> pd(d, std::free); 

The interface of smart pointers to single objects differs fundamentally from that of smart pointers to arrays:

  • A single object smart pointer often supports derived-to-base conversions while array smart pointers must not support such conversions.
  • A dereference operator for a single object makes sense but for an array it makes less sense because it will dereference only the first element.
  • Operator [] makes sense only for an array smart pointer.

The designers of unique_ptr solved these discrepancies by creating a partial specializationfor arrays:

unique_ptr<int[]> arrup (new int[3]);

The trailing [] after the type in the unique_ptr declaration indicates that the "array version" (no dereference, no conversions, indexing supported) shall be used. As expected, the default deleter here is delete[].

Elegant Smart
unique_ptr isn't just a safer alternative to the deprecated auto_ptr. It offers services that auto_ptrdoesn't support, including safe usage with containers and algorithms, customizable deleters, and array handling. Surprisingly, this versatility doesn't exact a performance toll; you only pay for what you're actually using.

Danny Kalev is a certified system analyst and software engineer specializing in C++. He was a member of the C++ standards committee between 1997 and 2000 and has since been involved informally in the C++0x standardization process. He is the author of "The ANSI/ISO Professional C++ Programmer's Handbook" and "The Informit C++ Reference Guide: Techniques, Insight, and Practical Advice on C++."
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.