Smart Pointers
When using raw pointers you might run into the following bugs:
- Memory leaks
- Freeing memory that shouldn’t be freed
- Freeing memory incorrectly
- Using memory that has not yet been allocated
- Thinking that memory is still allocated after being freed
That is why you need to use smart pointers.
std::unique_ptrExclusively owns a dynamically allocaed resource on the HEAPstd::shared_ptrPoints to a resource on a HEAP but does not explicitly own it. Has a reference count. Resource will be deallocated when count reaches zerostd::weak_ptrsame as shared but without reference count.
std::unique_ptr
std::unique_ptr<int> unique(new int); // create a unique pointer on the stack
*unique = 2; // assign a value
// delete is not neccessary
auto destPtr = std::move(unique);
// destPtr now owns the resource
std::shared_ptr
std::shared_ptr<int> ptr1(new int);
// cout << ptr1.use_count() = 1
{
std::shared_ptr<int> ptr2 = ptr1;
// cout << ptr1.use_count() = 2
}
// cout << ptr1.use_count() = 1
class MyClass {
};
int main() {
std::shared_ptr<MyClass> shared(new MyClass);
// cout << ptr1.use_count() = 1
shared.reset(new MyClass);
// cout << ptr1.use_count() = 1
}
- Problem with shared pointers: Circular references:
class MyClass
{
public:
std::shared_ptr<MyClass> _member;
~MyClass() { }
};
int main() {
std::shared_ptr<MyClass> myClass1(new MyClass);
std::shared_ptr<MyClass> myClass2(new MyClass);
myClass1->_member = myClass2;
myClass2->_member = myClass1;
}
std::weak_ptr
int main()
{
std::shared_ptr<int> mySharedPtr(new int);
// cout << mySharedPtr.use_count() = 1
std::weak_ptr<int> myWeakPtr1(mySharedPtr);
std::weak_ptr<int> myWeakPtr2(myWeakPtr1);
// cout << mySharedPtr.use_count() = 1
}
int main() {
std::shared_ptr<int> mySharedPtr(new int);
std::weak_ptr<int> myWeakPtr(mySharedPtr);
mySharedPtr.reset(new int);
if (myWeakPtr.expired() == true) {
std::cout << "Weak pointer expired!" << std::endl;
}
}
Conversion
int main() {
// construct a unique pointer
std::unique_ptr<int> uniquePtr(new int);
// (1) shared pointer from unique pointer
std::shared_ptr<int> sharedPtr1 = std::move(uniquePtr);
// (2) shared pointer from weak pointer
std::weak_ptr<int> weakPtr(sharedPtr1);
std::shared_ptr<int> sharedPtr2 = weakPtr.lock();
// (3) raw pointer from shared (or unique) pointer
int *rawPtr = sharedPtr2.get();
delete rawPtr;
}
´´´
## Recommendations
* Use unique_ptr or shared_ptr to represent ownership
* Prefer unique_ptr over std::shared_ptr unless you need to share ownership
* Use make_shared() to make shared_ptr
* Use make_unique() to make std::unique_ptr
* Use weak_ptr to break cycles of shared_ptr
## How to decide which pointer to use
* Do you want to be able to pass nullptr -> use f(object*)
* otherwise use f(object&)
* Express that the function is now responsible for the object f(unique_ptr<object>)
* Express that the function is sharing an object use f(shared_ptr<object>)
# Source
* [Udacity c++ nanodegree](https://www.udacity.com/course/c-plus-plus-nanodegree--nd213)
* [CppCoreGuidelines Smart pointers](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#rsmart-smart-pointers)