Smart pointers are defined in std namespace and <memory> header file.
- auto_ptr - no longer used in C++11
- unique_ptr - Allows exactly one owner of the underlying pointer. Can be moved to a new owner, but not copied or shared.
- shared_ptr - Reference-counted smart pointer. Use when you want to assign one raw pointer to multiple owners.
- weak_ptr - Special-case smart pointer for use in conjunction with shared_ptr. A weak_ptr provides access to an object that is owned by one or more shared_ptr instances, but does not participate in reference counting.
unique_ptr
An object can be owned by only one unique_ptr at a time by rejecting copy constructor and assignment operator. But actually we can call copy constructor or assignment operator of a unique_ptr about to be destroyed.
- use std::make_unique as possible, it is supported in c++14 not c++11
- use std::move to transefer the ownership of an object from unique_ptr to unique_ptr
- delete object by using reset() or set unique_ptr to nullptr
void UseRawPointer()
{
// Using a raw pointer -- not recommended.
Song* pSong = new Song(L"Nothing on You", L"Bruno Mars");
// Use pSong...
// Don't forget to delete!
delete pSong;
}
void UseSmartPointer()
{
// Declare a smart pointer on stack and pass it the raw pointer.
unique_ptr<Song> song2(new Song(L"Nothing on You", L"Bruno Mars"));
// Use song2...
wstring s = song2->duration_;
//...
} // song2 is deleted automatically here.
/******************************************************************************/
// operations of unique_ptr
std::unique_ptr<T> uptr; //empty unique_ptr with default deleter
std::unique_ptr<T,D> uptr(d); //empty unique_ptr with an input deleter to release memory
uptr = nullptr; // free the object and set up to nullptr
uptr.release(); // release the ownership of the object
// and return the reserved pointer
// set up to nullptr, but will not free the memory
uptr.reset(…); // free the previous object and reset a new object
/******************************************************************************/
// explicit ownership exchange
std::unique_ptr<Point> p1(new Point); // p1 owns the Point
std::unique_ptr<Point> p2; // p2 owns nothing
// invoke move assignment explicitly
p2 = std::move(p1); // now p2 owns Point, p1 owns nothing
// invoke move construction explicitly
std::unique_ptr<Point> p3(std::move(p2)); // now p3 owns it, p2 and p1 own nothing
// implicit ownership exchange
std::unique_ptr<Point> CreatePoint()
{
std::unique_ptr<Point> temp_ptr(new Point);
return temp_ptr;
}
void foo()
{
// Actually we can call copy constructor or assignment operator of a unique_ptr about to be destroyed
std::unique_ptr<Point> p1(CreatePoint());
}
About release() - remember to use the return pointer of release(), otherwise it will induce memory leak,
std::unique_ptr<int> func(unique_ptr<int> uptr)
{
return uptr;
}
// exchange the ownership and return it after the function
// if up does not take return of func() here, memory leak happens
up = func(unique_ptr<int> (up.release()));
Do not mix unique_ptr with raw pointers, use release() to get original pointer.
int *x = new int(5);
std::unique_ptr<int> uptr1, uptr2;
// uptr1 and uptr2 point to the same memory!!!
uptr1.reset(x);
uptr2.reset(x);
When using unique_ptr for an object without destructor, a definite deleter is needed.
shared_ptr
shared_ptr can share ownership of the object with the other shared_ptr.
The object will be freed only when:
- the last shared_ptr which reference to the object is destroyed
- shared_ptr call reset()
- shared_ptr is set to nullptr
std::shared_ptr<int> sp1(new int(2)); // sp1 owns int(2)
std::shared_ptr<int> sp2(sp1); // sp2 shares ownership of int(2)
std::shared_ptr<int> sp3;
sp3 = sp2; // sp3 also takes ownership of int(2)
int* p = sp3.get(); // return pointer which points to int(2)
sp1.reset(new int(3)); // sp1 takes ownership of int(3)
sp2.reset(new int(4)); // sp2 takes ownership of int(4)
sp3.reset(new int(5)); // sp3 takes ownership of int(5), and int(2) is freed
use make_shared as possible as you can to avoid revealing of raw pointer
//p1指向一个值为"9999999999"的string
std::shared_ptr<string> p1 = std::make_shared<string>(10, '9');
std::shared_ptr<string> p2 = std::make_shared<string>("hello");
std::shared_ptr<string> p3 = std::make_shared<string>();
static_pointer_cast/dynamic_pointer_cast/const_pointer_cast are available
do NOT create two smart pointer with same functionalities from the same raw pointer, it will induce double-deletion error
int* num = new int(10);
std::shared_ptr<int> sp1(num), sp2(num);
// can NOT do this !!!
// sp1 and sp2 will NOT share the same reference counter.
// so it will induce a double-deletion error.
weak_ptr
weak_ptr is used with shared_ptr, it will not add reference count.
- use weak_ptr to avoid issues induced by cicular reference of shared_ptr
- use expire() to check if object is valid
- use lock() to get the corresponding shared_ptr