智能指针

智能指针诞生的缘由:

在动态内存管理过程,要注意释放动态内存的正确时间,若是不释放的话,会形成内存泄露;可是释放时若还有指针引用内存的话,会产生引用非法内存的指针。而智能指针就是为了解决这一难点而诞生的,就如它的名字同样,若是你使用智能指针的话,它就会智能的在合适的时机释放掉内存。智能指针包括shared_ptr,unique_ptr和weak_ptr.安全

shared_ptr和unique_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_ptrcode

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和new结合使用:

shared_ptr的构造函数时explict修饰的,所以咱们不能将一个指针隐式转换为智能指针。作用域

shared_ptr<int>p = new int(10);//错误,不能将内置指针转换为智能指针
shared_ptr<int>p(new int(10));//ok

另外shared_ptr还支持reset操做来改变智能指针绑定的指针。get

p.reset();//p取消与指针的绑定,变成默认的nullptr;
p.reset(new int(20));//p与新的匿名地址绑定。

unique_ptr

unique_ptr与shared_ptr不一样的是,它不可以拷贝,也就是说它的计数器是能小于等于1.当unique_ptr被销毁的时候,它指向的对象也将被销毁。内存管理

unique不支持拷贝和赋值:io

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

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共享对象。
}

weak_ptr能够解决shared_ptr的循环引用:

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,释放内存。

相关文章
相关标签/搜索