unique_ptr :
一个unique_ptr"拥有"它所指向的对象,与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定对象,当unique_ptr被销毁时,它所指向的对象也被销毁,与shared_ptr不同,没有类似make_shared的标准库函数返回一个unique_ptr,当我们定义一个unique_ptr时,需要将其绑定到一个new返回的指针上初始化unique_ptr必须采用直接初始化形式。由于一个unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作。
unique_ptr<int> p2(new int(42));
unique_ptr<string> p1(new string("Stegosaurus"));
unique_ptr<string> p2(p1); //错误 unique_ptr不支持拷贝
unique_ptr<string> p3;
p3 = p2; //错误 unique_ptr不支持赋值
unique_ptr操作:
unique_ptr<T> u1 //空unique_ptr,可以指向类型为T的对象,u1会使用delete来释放它的指针
unique_ptr<T, D> u2 //u2会使用一个类型为D的可调用对象来释放它的指针
unique_ptr<T, D> u(d) //空unique_ptr,指向类型为T的对象,用类型为D的对象d代替delete
u.release() //u放弃对指针的控制权,返回指针,并将u置为空(不会主动释放内存) 要接受返回的指针,并进行释放(对返回的指针主动调用delete)
u.reset(q) //如果提供了内置指针q,令u指向这个对象
u.reset(nullptr) //或者u.reset(); 先将u所指向对象释放,然后将u置为空(会释放内存)
unique_ptr中的拷贝构造和赋值运算符重载函数被定义成删除函数了(=delete),虽然不能拷贝或赋值unique_ptr,但可以通过调用release或reset将指针的所有权从一个(非const)unique_ptr转移给另一个unique。
//将所有权从p1转移给p2
unique_ptr<string> p1(new string("Stegosaurus"));
unique_ptr<string> p2(p1.release()); //release将p1对指针的控制权交给p2后,将自己置为空
unique_ptr<string> p3(new string("Trex"));
//将所有权从p3转移给p2
p2.reset(p3.release()); //reset释放了p2原来指向的内存,转为指向原p3的内存
release成员返回unique_ptr当前保存的指针并将其置为空,因此,p2倍初始化为p1原来保存的指针,而p1置为空,reset成员接受一个可选的指针参数,令unique_ptr重新指向给定的指针,如果unique_ptr不为空,它原来指向的对象被释放,因此,对p2调用reset释放了用"Stegosaurus"初始化的string所使用的内存,将p3对指针的所有权转移给p2,并将p3置为空,调用release会切断unique_ptr和它原来管理的对象间的联系,release返回的指针通常被用来初始化另一个智能指针或给另一个智能指针赋值,在本例中,管理日常的责任简单的从一个智能指针转移给另一个,但是如果我们不用另一个智能指针来保存release返回的指针,我们的程序就要负责资源的释放。如果要释放内存,release完之后记得要对返回的指针进行delete。
p2.release(); //错误 不会释放内存,只是p2放弃了指针的控制权,而且我们丢失了指针
auto p = p2.release(); //正确 但我们必须记得delete(p)才能释放内存
传递unique_ptr参数和返回unique_ptr:
不能拷贝unique_ptr的规则有一个例外,我们可以拷贝或赋值一个将要被销毁的unique_ptr,最常见的例子是从函数返回一个unique_ptr,还可以返回一个局部对象的拷贝。
unique_ptr<int> clone(int p)
{
return unique_ptr<int>(new int(p));
}
unique_ptr<int> clone(int p)
{
unique_ptr<int> ret(new int(p));
return ret;
}
对于俩段代码,编译器都知道要返回的对象将要被销毁,在此情况下,编译器执行了一种特殊的“拷贝”。
weak_ptr:
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数,一旦最后一个指向对象的shared_ptr被销毁,对象就会释放,即使有weak_ptr指向对象,对象也还是会释放,因此weak_ptr的名字抓住了这种智能指针“弱”共享对象的特点。没有重载opreator*和->操作符,也就意味着即使分配到对象,他也没法使用该对象。
weak_ptr的操作:
weak_ptr<T> w //空weak_ptr可以指向类型为T的对象
weak_ptr<T> w(sp) //与shared_ptr sp指向相同对象的weak_ptr,T必须能够转换为sp指向的类型
w = p //p可以是一个shared_ptr或一个weak_ptr,赋值后w与p共享对象
w.reset() //将w置为空
w.use_count() //与w共享对象的shared_ptr的数量
w.expired() //若w.use_count() 为0,返回true,否则返回false
w.lock() //如果expired为true,返回一个空shared_ptr,否则返回一个指向w的对象的shared_ptr
当我们创建一个weak_ptr时,要用一个shared_ptr来初始化它。
auto p = make_shared<int>(42);
weak_ptr<int> wp(p); //wp弱共享p,p的引用计数未改变
由于对象可能不存在,我们不能使用weak_ptr直接访问对象,而必须调用lock,此函数检查weak_ptr指向的对象是否仍存在,如果存在,lock返回一个指向共享对象的shared_ptr,与任何其他shared_ptr类似,只要此shared_ptr存在,它所指向的底层对象也就会一直存在。