C++11
:auto_ptr,unique_ptr
,shared_ptr
,weak_ptr
Smart pointers can do virtually everything raw pointers can, but with far fewer opportunities for error.
unique_ptr
Use unique_ptr when you want to have single ownership (exclusive) of resource. When that unique_ptr is destructed, the resource is automatically released.
custom deleter
auto deleter = [](A* a){ ... delete a;} //lambda
unique_ptr<A, decltype(deleter)> A(new A, deleter)
move semantics
Unlike auto_ptr, copy assignment is not allowed for unique_ptr. Ownership is truly unique and safe. unique_ptr can be moved using the new move semantics:
unique_ptr<A> ptr1 (new A);
unique_ptr<A> ptr2 = std::move(ptr1);
shared_ptr
A shared_ptr is a container for a raw pointer. It is a reference counting ownership model i.e. it maintains the reference count of its contained pointer in cooperation with all copies of the shared_ptr. So, the counter is incremented each time a new shared_ptr points to the resource and decremented when the shared_ptr is destructed. An object will not be destroyed until all copies of shared_ptr have been destructed. So, we should use shared_ptr when we want to assign one raw pointer to multiple owners.
enable_shared_from_this
It enables you to get a valid shared_ptr instance to this. Without it, you would have no way of getting a shared_ptr to this, unless you already had one shared_ptr as a member.
class A: public enable_shared_from_this<A>
{
public:
shared_ptr<A> getMe() { return shared_from_this(); }
}
The method getMe() returns a valid shared_ptr. Note that you cannot simply do shared_ptr<A> getMe() { return shared_ptr<A>(this); }. Because the returned shared_ptr will have a different reference counting control, which will end up holding a dangling reference when the object is deleted.
weak_ptr
A weak_ptr is created as a copy of shared_ptr. It provides access to an object that is owned by one or more shared_ptr, but does not participate in reference counting. The existence or destruction of weak_ptr has no effect on the shared_ptr or its other copies. It is required in some cases to break circular references between shared_ptr instances.
circular dependency of shared_ptr
Consider a scenario where we have two objects A and B. A
has shared_ptr<B> b
and B
has shared_ptr<A> a
. Hence, use_count will never reach zero and they will never get deleted.
basic uses of weak_ptr
// created as a copy of shared_ptr
std::weak_ptr<Widget> w_ptr(s_ptr);
// check if w_ptr is valid
if (!w_ptr.expired()) {
// do something
}
// lock() creates a new shared_ptr that shares
// ownership of the managed object.
// If there is no managed object,
// the returned shared_ptr is also empty.
// i.e. expired() ? shared_ptr<T>() : shared_ptr<T>(*this)
if (auto s_ptr_2 = w_ptr.lock()) {
// do something
} else {
// do something
}
make_unique and make_shared
potential memory leak
processWidget(shared_ptr<Widget>(new Widget), getSomething());
It depends on compiler, if it firstly calls new Widget, then getSomething() and getSomething() throws an exception, Widget is leaked.
processWidget(make_shared<Widget>(), getSomething());
The correct way is as above.