对智能指针的理解和简单应用

        使用普通指针,容易造成堆内存泄露(忘记释放),二次释放,程序发生异常
时内存泄露等问题等,使用智能指针能更好的管理堆内存。

unique_ptr,shared_ptr, weak_ptr是三种C++11支持的常用的智能指针,接下来分别观察它们的性质和一些简单应用,体会一下:

shared_ptr(强引用):

        shared_ptr的实现:指向堆上创建的对象的裸指针(raw_ptr)和指向内部隐藏的、共享的管理对象(share_count_object)。

        PS:共享堆上对象的所有权,性能略差

①对shared_ptr的初始化优先使用make_share

auto sp1 = make_shared(100);//一次就能完成定义指针、长度分配
//相当于
shared_ptr sp1(new int(100));//先完成指针定义,再分配长度

②智能指针是一个包含指针和计数的结构体,不能直接像裸指针一样赋值

std::shared_ptr p = new int(1);//错误

那么通过这几个典型案例总结一下我们需要掌握的常用函数(注意注释),也是这几个指针的共性:

案例一(主动释放和被动释放):

#include 
#include 
using namespace std;

int main()
{
    auto sp1 = make_shared(100); // 优先使用make_shared来构造智能指针
    shared_ptr sp2(new int(100));
    std::shared_ptr p1;
    p1.reset(new int(1));  //reset有参数就是初始化,没参数就是释放(变0)
    std::shared_ptr p2 = p1;
    // ******引用计数此时应该是2,多次引用++操作

    cout << "p2.use_count() = " << p2.use_count()<< endl;
    p1.reset();   //主动释放
    cout << "p1.reset()\n";
    // 引用计数此时应该是1(即有多少个指针引用)
    cout << "p2.use_count()= " << p2.use_count() << endl;
    if(!p1) { //p1为空就是0
        cout << "p1 is empty\n";
    }
    if(!p2) {
        cout << "p2 is empty\n";
    }
    p2.reset();
    cout << "p2.reset()\n";
    cout << "p2.use_count()= " << p2.use_count() << endl;
    if(!p2) {
        cout << "p2 is empty\n";
    }
    return 0;
}

案例二(指定删除器):

        管理非new对象或是没有析构函数的类时,应当为其传递合适的删除器。

#include 
#include 
using namespace std;

void DeleteIntPtr(int *p) {
    cout << "call DeleteIntPtr" << endl;
    delete p;
}

int main()
{
    std::shared_ptr p(new int(1), DeleteIntPtr);//这里的删除器是一个函数
    std::shared_ptr p2(new int(1), [](int *p) {
        cout << "call lambda delete p" << endl;
        delete p;});//这里的删除器是一个lamda函数
    std::shared_ptr p3(new int[10], [](int *p) { delete []p;}); //若删除的是new type[](也就是动态数组),删除时加[]
    return 0;
}//这里要注意析构的顺序,以免造成一次删多个的崩溃(先外再内)

案例三(返回值是智能指针):

#include 
#include 

using namespace std;

class A: public std::enable_shared_from_this //这里不声明将会造成重复析构,因为同位置智能指
//针数量增加,但share_count_object不增加
{
public:
    shared_ptrGetSelf()
    {
        return shared_from_this(); 
    }
    ~A()
    {
        cout << "Deconstruction A" << endl;
    }
};

int main()
{
    //    shared_ptr sp1(new A);
    //    shared_ptr sp2 = sp1->GetSelf();  // ok
    shared_ptr sp2;
    {
        shared_ptr sp1(new A);
        sp2 = sp1->GetSelf();  // 通过share_from_this这个函数帮助打到count增加的目的
    }
    cout << "leave {}" << endl;

    return 0;
}

unique_ptr:

        unique_ptr是一个独占型的智能指针,它不允许其他的智能指针共享其内部的指针。通过代码理解一下。(用的比较少)

        Ps:独占对象的所有权,没有引用计数,性能较好

#include 
#include 
using namespace std;

void test1()
{
    unique_ptr my_ptr(new int); // 正确
    if(!my_ptr) {
        cout << "1 my_ptr is null" << endl ;
    
    unique_ptr my_other_ptr = std::move(my_ptr); // 正确,(unique的赋值)
                                                      //(把my_ptr资源移走)
    if(!my_ptr) {
        cout << "2 my_ptr is null" << endl ;
    }
}
void test2()
{
    //    unique_ptr可以指向一个数组
    std::unique_ptr ptr(new int[10]);
    ptr[9] = 9;

    //    std::shared_ptr ptr2(new int[10]);  // 这个是不合法的

    //    unique_ptr指定删除器和shared_ptr有区别
    std::shared_ptr ptr3(new int(1), [](int *p){delete  p;}); // 正确
    //    std::unique_ptr ptr4(new int(1), [](int *p){delete  p;}); // 错误

    std::unique_ptr ptr5(new int(1), [](int *p){delete  p;}); // 正确

    std::unique_ptr ptr6(new int(1), [](int *p){delete  p;}); // 正确
    cout << "main finish!" << endl;
}
int main()
{
    test1();
//    test2();
    cout << "main finish!" << endl;
    return 0;
}

weak_ptr(弱引用):

        share_ptr虽然已经很好用了,但是有一点share_ptr智能指针还是有内存泄露的情况,当两个对象相互使用一个shared_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄漏。

①weak_ptr 是一种不控制对象生命周期(不影响count)的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的shared_ptr, weak_ptr只是提供了对管理对象的一个访问手段

②weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少

③weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。weak_ptr是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。

案例一(强引用和弱引用的体现):

        只有强引用(发生死锁、不释放);

#include 
#include 
using namespace std;

class A;
class B;

class A {
public:
    std::shared_ptr bptr;
    ~A() {
        cout << "A is deleted" << endl;  //析构函数后,才会释放成员变量
    }
};

class B {
public:
    std::shared_ptr aptr;
    ~B() {
        cout << "B is deleted" << endl;
    }
};

int main()
{
    {
        std::shared_ptr ap(new A);
        std::shared_ptr bp(new B);
        ap->bptr = bp;
        bp->aptr = ap;
        // 是否可以手动释放呢?-----是可以的
        //ap.reset()or bp.reset();
    }
    cout<< "main leave" << endl;  // 循环引用导致ap bp退出了作用域都没有析构
    return 0;
}

        强弱引用混合:

#include 
#include 
using namespace std;


void test1()
{
    cout << "---- test1 ------------------" << endl;
    weak_ptr wp;
    {
        shared_ptr  sp(new int(1));  //sp.use_count()==1
        wp = sp;                            //wp不会改变引用计数,所以sp.use_count()==1
        shared_ptr sp_ok = wp.lock(); //wp没有重载->操作符。只能这样取所指向的对象
    }
    shared_ptr sp_null = wp.lock(); //sp_null .use_count()==0;
    if(wp.expired()) {//weap 不能直接操作成员变量
        cout << "shared_ptr is destroy" << endl;
    } else {
        cout << "shared_ptr no destroy" << endl;
    }
}

void test2()
{
    cout << "---- test2 ------------------" << endl;
    weak_ptr wp;
    shared_ptr sp_ok;
    {
        shared_ptr  sp(new int(1));  //sp.use_count()==1
        wp = sp; //wp不会改变引用计数,所以sp.use_count()==1
        sp_ok = wp.lock(); ****//不能直接赋值,需要借助lock获取
    }

    if(wp.expired()) {
        cout << "shared_ptr is destroy" << endl;
    } else {
        cout << "shared_ptr no destroy" << endl;
    }
}
int main()
{
    test1();
    test2();
    return 0;
}

你可能感兴趣的:(c++)