智能指针 --- 一

C++中的智能指针是用来管理外界资源的,如在堆上边new的资源,当程序还没来得及执行delete操作,函数遇到异常了,没有释放资源,导致内存泄露      如下代码:

void fun()
{
    A *ptr = new A();
    /*...
    ...*/           //程序可能在这行代码中抛出异常,导致ptr所指向堆上的资源没有释放
    delete ptr;
}

智能指针是怎么解决这个问题的

智能指针在实现上也是一个类,即有构造函数、析构函数,在函数结束之前 类会自动调用析构函数,析构函数会释放资源,所以当遇到异常时,资源也会被正确的释放掉。

接下来介绍 auto_ptr、unique_ptr、 share_ptr、weak_ptr四种智能指针

auto_ptr 

auto_ptr是弱智能指针  一个资源只能被一个auto_ptr拥有,当智能指针赋值的时候拥有权就会发生转移,如下代码

因为会发生所有权的转移所以auto_ptr不能用在STL标准容器中

void Fun(auto_ptr<A> &ptr)
{
    cout << ptr -> a << endl;
    cout << "Fun faction end" << endl;
}

//auto_ptr
void Test()
{
    auto_ptr<A> aptr(new A(5));
    auto_ptr<A> bptr;
    bptr = aptr;                //赋值运算符重载函数
    auto_ptr<A> cptr(bptr);     //拷贝构造函数
    Fun(cptr);       //会导致aptr失效,将aptr对资源的拥有权转向了ptr智能指针
    cout << cptr -> a << endl;
}

 

share_ptr:

share_ptr  资源可以被多个指针共享,share_ptr 使用引用计数对资源管理, 不可以调用release(), 调用reset()函数当前的share_ptr会释放资源的所有权,引用计数减一,当引用计数为0时,没有指针指向该资源,资源会被释放, 因为资源可以被多个指针指向,所以指针可以赋值、在函数之间传递,存放在STL容器里,  use_count() 返回当前指针指向资源的引用计数(use_count()的效率不高)。

share_ptr使用不当会出现循环引用,资源得不到释放,暂时先不看这个问题。

下边时使用share_ptr的相关代码

示范一:

class A{};
shared_ptr<A> aptr(new A());
shared_ptr<A> bptr = aptr;
    
cout << aptr.use_count() << endl;

输出

A()
2
~A()

示范二:

A *a = new A();
shared_ptr<A> aptr(a);
shared_ptr<A> bptr = aptr;

//这样写会报错,导致堆上的同一资源被delete了两次
/*A *a = new A();
shared_ptr<A> aptr(a);
shared_ptr<A> bptr(a);*/

unique_ptr

c++11弃用了auto_ptr,unique_ptr替代了auto_ptr,在同一时刻只有一个unique_ptr指向给定的对象,该智能指针是禁止使用拷贝构造函数的 禁止使用赋值运算符重载函数 

  • 只能使用move()函数对对象的所有权进行转移,
  • reset()函数用来重新指定资源
  • release 释放所有权
void Fun(unique_ptr<A>& ptr)   //必须写成引用
{
    cout<< ptr -> a << endl;
}

//unique_ptr
void Test1()
{
    unique_ptr<A> aptr(new A(10));
    unique_ptr<A> bptr;
//    bptr = aptr;                //error
//    unique_ptr<A> cptr(aptr);   //error
    bptr = move(aptr);
    cout<< bptr -> a << endl;
    aptr.reset(new A(20));
    cout<< aptr -> a << endl;
    Fun(aptr);
    aptr.release();
//    cout<< aptr -> a << endl;  //error
    cout<< "Test1() end" <<endl;
}

 

weak_ptr

weak_ptr 弱智能指针,能看到资源的引用计数,但是不会去用这个引用计数,使用weak_ptr指向资源不会使引用计数增加。

为了配合shared_ptr而引入了weak_ptr,weak_ptr是从share_ptr 或 从另一个weak_ptr对象那里构造,不能直接指向一个新new出来的资源,weaker_ptr可以观察资源的引用情况,他没有重载* 和 -> 运算符。   use_count()函数返回资源的引用计数。 在weak_ptr智能指针类中可以有一个成员函数 lcok();  该函数的作用是从被观测的对象返回一个可用的shared_ptr对象,可以将这个对象赋值给一个新的shred_ptr智能指针.

示范代码如下:

//weak_ptr
void Test2()
{
    shared_ptr<A> aptr(new A(10));
    shared_ptr<A> bptr(aptr);
    weak_ptr<A> wptr(aptr);
    cout << wptr.use_count() << endl;
    shared_ptr<A> cptr = wptr.lock();    //获得shared_ptr对象
    cout << cptr -> a << endl;
    cout << wptr.use_count() << endl;    //获得引用计数

    aptr.reset(new A(20));               //重新指向一个新的资源
    cout << aptr -> a << endl;


    aptr.reset();                        //指向一个空的资源
    bptr.reset();
    cptr.reset();
    cout << wptr.use_count() << endl;
    shared_ptr<A> dptr = wptr.lock();   //当堆上的对象引用计数为0,被释放的时候,weak_ptr调用lock()返回一个指针空值(nullptr)
    cout << dptr.use_count() << endl;

}

在所有的智能指针中析构函数调用的是delete,不是delete[]; 所以在创建智能指针的时候不可以写成 new A[10]; 不能new一个数组,导致资源释放的时候发生错误

整体的代码稍后传到Github上

下一篇总结强智能指针shared_ptr引起的循环引用,weak_ptr配合shared_ptr的案例之一.

之后会把Effective C++上对智能指针的条例总结到后续博客中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章