In modern C++ programming, the Standard Library includes smart pointers,
which are used to help ensure that programs are free of memory and resource leaks and are exception-safe.
1 Uses for smart pointers
Smart pointers are defined in the std namespace in the header file.
They are crucial to the RAII or Resource Acquisition Is Initialialization programming idiom.
The main goal of this idiom is to ensure that resource acquisition occurs at the same time that the object is initialized,
so that all resources for the object are created and made ready in one line of code.
Declare the smart pointer as an automatic (local) variable. (Do not use the ‘new’ or ‘malloc’ expression on the smart pointer itself.)
In the type parameter, specify the pointed-to type of the encapsulated pointer.
Pass a raw pointer to a new-ed object in the smart pointer constructor.
Use the overloaded -> and * operators to access the object.
Let the smart pointer delete the object.
Smart pointers have their own member functions, which are accessed by using ‘dot’ notation.
Smart pointers usually provide a way to access their raw pointer by get() member function directly.
A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr, passed by value to a function, or used in any C++ Standard Library algorithm that requires copies to be made.
A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to another unique_ptr and the original unique_ptr no longer owns it.
The following example shows how to create unique_ptr instances and pass them between functions.
The following example shows how to create unique_ptr instances and use them in a vector.
The following example shows how to initialize a unique_ptr that is a class member.
You can use make_unique to create a unique_ptr to an array, but you cannot use make_unique to initialize the array elements.
The shared_ptr type is a smart pointer in the C++ standard library that is designed for scenarios in which more than one owner might have to manage the lifetime of the object in memory.
After you initialize a shared_ptr you can copy it, pass it by value in function arguments, and assign it to other shared_ptr instances.
All the instances point to the same object, and share access to one “control block” that increments and decrements the reference count
whenever a new shared_ptr is added, goes out of scope, or is reset. When the reference count reaches zero, the control block deletes the memory resource and itself.
Whenever possible, use the make_shared function to create a shared_ptr when the memory resource is created for the first time.
The following example shows how to declare and initialize shared_ptr instances that take on shared ownership of an object that has already been allocated by another shared_ptr.
Assume that sp2 is an initialized shared_ptr.
shared_ptr is also helpful in C++ Standard Library containers when you are using algorithms that copy elements.
You can wrap elements in a shared_ptr, and then copy it into other containers with the understanding that the underlying memory is valid as long as you need it, and no longer.
The following example shows how to use the remove_copy_if algorithm on shared_ptr instances in a vector.
You can use dynamic_pointer_cast, static_pointer_cast, and const_pointer_cast to cast a shared_ptr.
These functions resemble the dynamic_cast, static_cast, and const_cast operators.
The following example shows how to test the derived type of each element in a vector of shared_ptr of base classes, and then copy the elements and display information about them.
Sometimes an object must store a way to access the underlying object of a shared_ptr without causing the reference count to be incremented.
Typically, this situation occurs when you have cyclic references between shared_ptr instances.
The best design is to avoid shared ownership of pointers whenever you can.
However, if you must have shared ownership of shared_ptr instances, avoid cyclic references between them.
When cyclic references are unavoidable, or even preferable for some reason, use weak_ptr to give one or more of the owners a weak reference to another shared_ptr.