在动态内存管理过程,要注意释放动态内存的正确时间,如果不释放的话,会造成内存泄露;但是释放时若还有指针引用内存的话,会产生引用非法内存的指针。而智能指针就是为了解决这一难点而诞生的,就如它的名字一样,如果你使用智能指针的话,它就会智能的在合适的时机释放掉内存。智能指针包括shared_ptr,unique_ptr和weak_ptr.
shared_ptr和unique_ptr支持的操作;
shared_ptr<T>sp; //T为参数类型,默认为空指针
unique_ptr<T>up;
*p;//解引用
p->get();//返回智能指针保存的指针
swap(p,q);//交换p和q种的指针
//构造一个shared_ptr
make_shared<T>(arg);//返回一个shared_ptr对象,并用arg来初始化它
shared_ptr<T>p(q);//用q来初始化p
p.use_count();//返回p种的计数。
我们可以认为每个智能指针都有绑定一个计数器,通常称其为引用计数。无论我们何时拷贝一个智能指针,计数器都会递增,例如
①用一个shared_ptr初始化另一个shared_ptr
shared_ptr<T>p(q);//q中的计数器会加一
②将智能指针作为参数传递
int func(std::shared_ptr<int>p){
return p->use_count();
}
int mian(){
std::shared_ptr<int>p = std::make_shared<int>(10);
std::cout<<func(p);//输出的结果为2
}
③作为参数的返回值:
shared_ptr<T> func();
shared_ptr的构造函数时explict修饰的,因此我们不能将一个指针隐式转换为智能指针。
shared_ptr<int>p = new int(10);//错误,不能将内置指针转换为智能指针
shared_ptr<int>p(new int(10));//ok
另外shared_ptr还支持reset操作来改变智能指针绑定的指针。
p.reset();//p取消与指针的绑定,变成默认的nullptr;
p.reset(new int(20));//p与新的匿名地址绑定。
unique_ptr与shared_ptr不同的是,它不能够拷贝,也就是说它的计数器是能小于等于1.当unique_ptr被销毁的时候,它指向的对象也将被销毁。
unique不支持拷贝和赋值:
std::unique_ptr<int>p(new int(10));//ok,直接初始化。
std::unique_ptr<int>q(p);//错误,不能拷贝
q = p;//错误,不能赋值
unique支持reset和release操作:
reset的操作和shared_ptr的reset操作相同,release操作会返回当前智能指针保存的对象并将智能指针置为空。通过这两个操作可以进行unique_ptr指向对象的专业。
p.reset(q.release());//将q保存的对象转移给p。
shared_ptr和unique_ptr默认为用delete删除对象,也可以自定义删除器
shared_ptr的自动删除器定义如下:
假设现在有class 为connection,删除函数为disconnect(connection *con);那么自动删除定义删除器为:
std::shared_ptr<connection>p(new connection(),disconnect);
//第二个参数为自定义的删除器函数。
unique_ptr的自动删除器要在参数列表指明删除器的函数指针类型,这里用decltype函数自动推导。
std::unique_ptr<connection,decltype(disconnect)*>p
(new connection(10),disconnect);
weak_ptr是一种不控制对象生长周期的智能指针,它指向一个shared_ptr指向的对象,将weak_ptr绑定到一个shared_ptr保存的对象上,也不会增加shared_ptr的计数器。一旦最后一个指向对象的shared_ptr被销毁,对象将被释放,即使还有weak_ptr绑定这个对象。
std::shared_ptr<int>p(new int(10));
std::weak_ptr<int>wp(p);//wp若共享p,p的引用计数不会改变
由于对象不存在,所以不能用wp直接访问对象,而是用成员函数lock来检查指向的对象是否存在,lock就返回一个指向的shared_ptr.与其它shared_ptr不同,只要此shared_ptr存在,它的底层对象就一直存在。
if(shared_ptr<int>np = wp.lock())//只有np不为空时才能进入if
{
//在if中使用共享对象np是安全的,np和p共享对象。
}
class B;
class A{
public:
A(){
std::cout<<"A construction"<<std::endl;
}
~A(){
std::cout<<"A destruction"<<std::endl;
}
std::shared_ptr<B>pb;
};
class B{
public:
B(){
std::cout<<"B construction"<<std::endl;
}
~B(){
std::cout<<"B destruction"<<std::endl;
}
std::shared_ptr<A>pa;
};
int main(){
std::shared_ptr<A>a(new A());
std::shared_ptr<B>b(new B());
a->pb = b;
b->pa = a;
}
上面的代码的输出是什么呢?
A construction
B construction
没错,可以很显然的看到A和B在主函数结束后并没有被销毁,因为A和B互相持有对方的引用计数,两者的引用计数都不会较小到0,因此内存也不会被释放。
而将代码修改到如下后:
class B;
class A{
public:
A(){
std::cout<<"A construction"<<std::endl;
}
~A(){
std::cout<<"A destruction"<<std::endl;
}
std::weak_ptr<B>pb;
};
class B{
public:
B(){
std::cout<<"B construction"<<std::endl;
}
~B(){
std::cout<<"B destruction"<<std::endl;
}
std::weak_ptr<A>pa;
};
int main(){
std::shared_ptr<A>a(new A());
std::shared_ptr<B>b(new B());
a->pb = b;
b->pa = a;
}
输入为
A construction
B construction
B destruction
A destruction
前面我们说过weak_ptr时弱共享,不会增加shared_ptr的计数引用,因此A和B只有本身一个计数引用,当自身离开作用域后,计数器归0,释放内存。
原文:https://www.cnblogs.com/Emiria/p/14327595.html