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.