Pages

Wednesday, December 30, 2015

Built-in Smart Pointers in Modern C++

C++ is a general programming language that supports raw pointers. To use the raw pointers, we have to manage the memory carefully with new/delete, new[]/delete[], or perhaps C-style malloc/free pairs. The memory leak is always a potential risk -- imagine a runtime_error just occurred. Detecting tools like Valgrind or Garbage Collectors like Boehm GC[using mark-sweep algorithm] may be helpful to some extent, but it's still our responsibilities to make sure that the memory is properly managed and thus less time is left for the actual business needs.

Smart pointer is one answer in the language level. Actually, smart pointers were introduced in C++98. With the move semantics, they got even better in C+11.

Topics in C++ built-in smart pointers could be intricate if we dig them further deep into areas, such as GC algorithms, thread safety and exception safety. In this post, I'll compare the various smart pointers in a high level, and summarize it in a simple table. For the detailed discussion and the guidelines to use them, please refer to Chapter 4 of Scott Meyers' "Effective Modern C++", or <memory> on cplusplus.com.


raw pointer
auto_ptr
unique_ptr
shared_ptr
weak_ptr
Language support
Always allowed
Deprecated in C++11
C++11 (replacing auto_ptr)
C++11
C++11
What are they
T* t
T *t[n]

Wrapper of raw pointer
·   A smart ptr uniquely owned -- no two unique_ptr instances manage one object
·   It provides a limited GC
·   It contains a stored ptr and a stored deleter.
 .  Move-only type.
·  A smart ptr shared ownership group
·   It contains a stored ptr and an owned ptr to control block.
·  Stored and owned ptrs may refer to one object.
·   Empty shared_ptr
·   Null shared_ptr
·  A smart ptr holding non-owning ref. to an object managed by shared_ptr.
·   It models the temp ownership


Use Cases
Almost never in practice
Prefer to unique_ptr
 .  A ptr w/ exclusive ownership.
 .  Used in Pimpl idiom
 .  A ptr w/ shared ownership.
 .  A shared_ptr like ptr in risk of dangling.

How to use
new/delete
new[]/delete[]


up = make_unique<T>();//C++14
up = make_unique<T[]>();
up.get_deleter();
T* rp = up.get();
T* rp = up.release();
up.reset(p);//destroy & own p
*up
up->v1
shared_ptr<T> up{move(up)};
sp = make_shared<T>(n);
sp = make_shared<T[]>(n);
sp.use_count()
sp.unique()?
T* rp = sp.get(); // stored ptr
sp.reset();
*sp
sp->v1
sp1=allocate_shared<T>(alloc,10);
weak_ptr<T> wp(sp);
sp1=wp.lock()
wp.use_count()
wp.expired()?
wp.reset();

Pros


·   Small and fast. Little overhead over raw pointer.
·  Easy to convert to shared_ptr
 . Allowed to custom deleter (using lambda expression)
 . Capture closure support
 . Low overhead (2 x unique_ptr)
 . Works in multi-threaded 
       environments.
 .  Prevent shared_ptr cycles.
 .  shared_ptr <==> weak_ptr
Cons


·  Not capoyable
 .  Circular reference
 .  Exception: bad_weak_ptr



"The present is the past rolled up for action, and the past is the present unrolled for understanding." - Will Durant. 

No comments:

Post a Comment