Built-in Smart Pointers in Modern C++ (original) (raw)
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 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();//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 up{move(up)}; | sp = make_shared(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(alloc,10); | weak_ptr 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.