一、auto_ptr
auto_ptr这是C++98标准下的智能指针,现在常常已经被C++标准的其他智能指针取代。它的缺点是在转移所有权后会使运行期不安全。C++11新标准,用unique_ptr来代替auto_ptr原有功能。
auto_ptr <double> pd;
double *p_reg = new double;
pd = p_reg; // 不允许
pd = auto_ptr <double> (p_reg); //允许
auto_ptr <double> panto =p_reg; //不允许
auto_ptr <double> pauto (p_reg); //允许
二、share_ptr
share_ptr是C++11新添加的智能指针,它限定的资源可以被多个指针共享。
只有指向动态分配的对象的指针才能交给 shared_ptr 对象托管。将指向普通局部变量、全局变量的指针交给 shared_ptr 托管,编译时不会有问题,但程序运行时会出错,因为不能析构一个并没有指向动态分配的内存空间的指针。
#include <iostream>
#include <memory>
#include <string>
using namespace std;
void fun() {
shared_ptr<string> pa(new string("CHN"));
shared_ptr<string> pb(new string("USA"));
cout << "*pa " << *pa << endl;//CHN
cout << "pa.use_count " << pa.use_count() << endl;//1
cout << "*pb " << *pb << endl;//USA
cout << "pb.use_count " << pb.use_count() << endl;//1
pa = pb;
cout << *pa << endl;//USA
cout << "pa.use_count " << pa.use_count() << endl;//2:pa和pb指向同一个资源USA了,该资源的计数为2,所以pb、pb都输出2
cout << "pb.use_count " << pb.use_count() << endl;//2
pa.reset();
pb.reset();
cout << "pa.use_count " << pa.use_count() << endl;//0
cout << "pb.use_count " << pb.use_count() << endl;//0
}
int main()
{
fun();
system("pause");
return 0;
}
输出结果:
*pa CHN
pa.use_count 1
*pb USA
pb.use_count 1
USA
pa.use_count 2
pb.use_count 2
pa.use_count 0
pb.use_count 0
注意,不能用下面的方式使得两个 shared_ptr 对象托管同一个指针:
A* p = new A(10);
shared_ptr <A> sp1(p), sp2(p);
sp1 和 sp2 并不会共享同一个对 p 的托管计数,而是各自将对 p 的托管计数都记为 1(sp2 无法知道 p 已经被 sp1 托管过)。这样,当 sp1 消亡时要析构 p,sp2 消亡时要再次析构 p,这会导致程序崩溃。
三、weak_ptr
weak_ptr是一种用于解决shared_ptr相互引用时产生死锁问题的智能指针。如果有两个shared_ptr相互引用,那么这两个shared_ptr指针的引用计数永远不会下降为0,资源永远不会释放。weak_ptr是对对象的一种弱引用,它不会增加对象的use_count,weak_ptr和shared_ptr可以相互转化,shared_ptr可以直接赋值给weak_ptr,weak_ptr也可以通过调用lock函数来获得shared_ptr。
- weak_ptr指针通常不单独使用,只能和 shared_ptr 类型指针搭配使用。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象也还是会被释放。
- weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象,典型的用法是调用其lock函数来获得shared_ptr示例,进而访问原始对象。
先看一下两个shared_ptr指针互相引用导致的资源释放失败的例子:
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class B;
class A
{
public:
shared_ptr<B> pb_;
~A()
{
cout << "A delete\n";
}
};
class B
{
public:
shared_ptr<A> pa_;
~B()
{
cout << "B delete\n";
}
};
void fun() {
shared_ptr<B> pb(new B());
cout << "pb.use_count " << pb.use_count() << endl;//1
shared_ptr<A> pa(new A());
cout << "pa.use_count " << pa.use_count() << endl;//1
pb->pa_ = pa;
cout << "pb.use_count " << pb.use_count() << endl;//1
cout << "pa.use_count " << pa.use_count() << endl;//2
pa->pb_ = pb;
//由于share_ptr是共享资源,所以pb所指向的资源的引用计数也会加1
cout << "pb.use_count " << pb.use_count() << endl;//2
cout << "pa.use_count " << pa.use_count() << endl;//2
}//程序结束时,没有调用A和B的析构函数
int main()
{
fun();
system("pause");
return 0;
}
输出结果:
pb.use_count 1
pa.use_count 1
pb.use_count 1
pa.use_count 2
pb.use_count 2
pa.use_count 2
而使用weak_ptr:把A中的shared_ptr<B> pb_改为weak_ptr<B> pb_weak,这样改为了弱引用,传递时不会增加pb引用计数use_count()的值,所以最终能够使A、B资源正常释放:
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class B;
class A
{
public:
weak_ptr<B> pb_weak;
~A()
{
cout << "A delete\n";
}
};
class B
{
public:
shared_ptr<A> pa_;
~B()
{
cout << "B delete\n";
}
void print() {
cout << "This is B" << endl;
}
};
void fun() {
shared_ptr<B> pb(new B());
cout << "pb.use_count " << pb.use_count() << endl;//1
shared_ptr<A> pa(new A());
cout << "pa.use_count " << pa.use_count() << endl;//1
pb->pa_ = pa;
cout << "pb.use_count " << pb.use_count() << endl;//1
cout << "pa.use_count " << pa.use_count() << endl;//2
pa->pb_weak = pb;
cout << "pb.use_count " << pb.use_count() << endl;//1:弱引用不会增加所指资源的引用计数use_count()的值
cout << "pa.use_count " << pa.use_count() << endl;//2
shared_ptr<B> p = pa->pb_weak.lock();
p->print();//不能通过weak_ptr直接访问对象的方法,须先转化为shared_ptr
cout << "pb.use_count " << pb.use_count() << endl;//2
cout << "pa.use_count " << pa.use_count() << endl;//2
}//函数结束时,调用A和B的析构函数
//资源B的引用计数一直就只有1,当pb析构时,B的计数减一,变为0,B得到释放,
//B释放的同时也会使A的计数减一,同时pa自己析构时也会使资源A的计数减一,那么A的计数为0,A得到释放。
int main()
{
fun();
system("pause");
return 0;
}
输出结果:
pb.use_count 1
pa.use_count 1
pb.use_count 1
pa.use_count 2
pb.use_count 1
pa.use_count 2
This is B
pb.use_count 2
pa.use_count 2
B delete
A delete
四、unique_ptr
unique_ptr 是一个独享所有权的智能指针,它提供了严格意义上的所有权。它取代了C++98中的auto_ptr。
unique_ptr对象包装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联的原始指针。
unique_ptr具有->和*运算符重载符,因此它可以像普通指针一样使用。
不管函数正常退出还是异常退出(由于某些异常),也会始终调用taskPtr的析构函数。因此,原始指针将始终被删除并防止内存泄漏。
用法和auto_ptr类似,详情见一下代码:
#include <iostream>
#include <memory>
using namespace std;
struct Task {
int mId;
Task(int id) :mId(id) {
cout << "Task::Constructor" << endl;
}
~Task() {
cout << "Task::Destructor" << endl;
}
};
int main()
{
// 通过原始指针创建 unique_ptr 实例
//shared_ptr<Task> taskPtr(new Task(23));
//int id = taskPtr->mId;
//调用其lock函数来获得shared_ptr示例,进而访问原始对象。
//weak_ptr<Task> weak1 = taskPtr;
//int id = weak1.lock()->mId;
unique_ptr<Task> taskPtr(new Task(23));
int id = taskPtr->mId;
cout << id << endl;
return 0;
}
输出结果:
Task::Constructor
23
Task::Destructor