C++ Tips - Smart Pointer

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

Reference

Microsoft Docs - Smart Pointers

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值