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.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

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++."
Thanks for your registration, follow us on our social networks to keep up-to-date