Boost的理解shared_ptr 和 weak_ptr

Boost库(智能指针)

智能:将所申请到的空间交由一个对象去管理,预防程序中出现异常或者由于自己忘记释放所申请的空间,造成内存泄漏的问题。 通过对*和->的重载,使其对象具有指针的特性 。

头文件 #include;

auto_ptr vc版本

利用一个字段判断拥有权,转移时要释放原有空间

VC版的实现:拥有权的转移,_Owns(此成员起的作用)。

缺点:在_Owns为1/0时(这个牵扯到释放空间),*pa对象都可访问,就是那个地址还保留着,转移的不彻底,存在安全隐患!

linux版本没有了转移权这个字段,比vc版的好

scoped_ptr ( 局部智能指针 )

scoped_ptr是一个很类似auto_ptr的智能指针,但是scoped_ptr的所有权更加严格,不能转让,一旦scoped_ptr获取了对象的管理权,你就无法再从它那里取回来。

#include<boost/smart_ptr.hpp> //:在include目录下的boost目录下的smart_ptr.hpp;

对空间的管理权不能交由其它对象,不能进行拷贝构造和赋值。

如何达到拥有权不能转移的目的,拷贝构造和赋值语句声明为私有的,不需要实现。

**缺点:不能对数组空间进行管理。 **

scoped_array

是专门对数组空间进行管理的。包装了new[]在堆上分配的动态数组;

scoped_array弥补了标准库中没有指向数组的智能指针的缺憾。

2、此类特点如下:

(1)、构造函数接受的指针p必须是new[]的结果,不能是new;

(2)、没有*、->操作符的重载(库中不提供这些的重载,但是我们可以自己写),因为scoped_array所持有的不是一个普通的指针;

(3)、析构则必须用delete [];

(4)、提供operator[]的重载,可以像普通数组一样进行下标访问元素;

(5)、没有begin()、end()等类似容器的迭代器操作函数;

scoped_array与scoped_ptr有相同的设计思想,也是局部智能指针,不能拷贝和赋值;

缺点:不能动态增长,没有迭代器支持,不能搭配STL算法,是纯粹的裸接口,不推荐使用。

shared_ptr( 共享性智能指针 )

shared_ptr是一个最像指针的“智能指针”,是boost.smart_ptr库中最有价值,最重要,也是最有用的。 shared_ptr也可以被安全的放到标准容器中;

有什么用 — 防止内存泄露

#include<iostream>
#include<algorithm>
#include<memory>
using namespace std;

class A {
public:
    A() {
        cout << "default constructor" << endl;
    }
    ~A() {
        cout << "destructor" << endl;
    }
};

int main() {
    A *p1 = new A();
    p1 = nullptr;  //此时发生内存泄露  调用不到析构函数  当前进程找不到了
    shared_ptr<A> p2(new A());
    shared_ptr<A> p3 = p2;
    cout<<ps.unique()<<endl; //判断对空间是否唯一,
    cout << p3.use_count() <<endl;  //有两个指向
    p3 = nullptr;  //还剩一个指向
    p2 = nullptr; // 自动析构    有一个引用计数

    return 0;
}

实现

重载 -> 符号 加一个引用计数(如果用整数的话,属性跟着对象的会有bug)

得用一个地址去存, 这样每个指针对象去操作的时候里面存的值才会跟着变

重载=符号 当赋值为nullptr引用计数减一 当赋值为同一个对象指针引用计数加一 当当前指针被赋值为其他前减一后如果引用计数为零了要delete然后再对赋值对象加一

#include<iostream>
#include<algorithm>
#include<memory>
using namespace std;

namespace xiaorun {
class A {
public:
    A() {
        cout << "default constructor" << endl;
    }
    ~A() {
        cout << "destructor" << endl;
    }

    int x = 1, y = 2;
};

class shared_ptr {
public:
    shared_ptr();
    shared_ptr(A *);
    shared_ptr(const shared_ptr &);
    A *operator->();     
    A &operator*();
    int use_count();
    shared_ptr &operator=(const shared_ptr &);
    ~shared_ptr();

private:
    void decrease_by_one();   //封装的引用计数减一操作
    void increase_by_one();   //封装的引用计数加一操作
    A *obj;
    int *cnt;    //一个地址存计数
};

shared_ptr::shared_ptr():obj(nullptr), cnt(nullptr) {}
shared_ptr::shared_ptr(A *obj):obj(obj), cnt(new int(1)) {}
shared_ptr::shared_ptr(const shared_ptr &p) : obj(p.obj), cnt(p.cnt){increase_by_one();}
int shared_ptr::use_count() {return cnt ? *cnt : 0;}
A *shared_ptr::operator->() {return obj; }
A &shared_ptr::operator*() { return *obj; }

shared_ptr &shared_ptr::operator=(const shared_ptr &p) {
    if (this->obj != p.obj) {
        decrease_by_one();
        obj = p.obj;
        cnt = p.cnt;
        increase_by_one();
    }
    return *this;
}
void shared_ptr::decrease_by_one() {
    if (this->cnt != nullptr) {
        *(this->cnt) -= 1;
        if (*(this->cnt) == 0) {
            delete this->obj;
            delete this->cnt;
        }
    }
    return ;
}
void shared_ptr::increase_by_one() {
    if (cnt != nullptr) {
        cnt[0] += 1;
    }
    return ;
}
shared_ptr::~shared_ptr() {
    this->decrease_by_one();
    this->obj = nullptr;
    this->cnt = nullptr;
}

};


int main() {
    xiaorun::A *p1 = new xiaorun::A();
    xiaorun::shared_ptr p2(new xiaorun::A());
    cout << p2.use_count() << endl;//1
    xiaorun::shared_ptr p3 = p2;
    p2->x = 123; p2->y = 456;
    (*p2).x = 456;
    cout << p2.use_count() << endl;//2
    p2 = nullptr; 
    cout << p3.use_count() << endl;//1
    p2 = p3;
    cout << p2.use_count() << endl;
    return 0;
}


使用注意事项
#include<iostream>
#include<algorithm>
#include<memory>
using namespace std;

int main() {
    //int *p = new int[10];//申请空间要放在构造函数里
    {
    //shared_ptr<int> ps(p);
    shared_ptr<int> ps(new int[10]);
        {
            //shared_ptr<int> ps1(p);  //这样会导致对p重复析构
            shared_ptr<int> ps1 = ps;
        }
    }
    return 0;
}

shared_array

shared_array的接口和功能与shared_ptr几乎是相同的,主要区别:

(1)、接受指针p必须是new []的结果

(2)、提供operator[]的重载,可以使用下标

(3)、系统没有提供*、->的重载

(4)、析构函数使用delete [];

可以在shared_ptr重载[]

weak_ptr

(1)、weak_ptr是为了配合shared_ptr而引入的智能指针,它更像是shared_ptr的一个助手,它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。

(2)、2个重要接口:bool expired()const ;// 判断是否过期

​ lock()函数是弱指针的核心;

(3)、获得资源的观测权,但weak_ptr没有共享资源,它的构造不会引起引用计数的增加,它的析构也不会导致引用计数减少,它只是一个静静的观察者。

为什么会有weak_ptr

为了避免循环引用问题

当用了shared_ptr 进行循环引用时会出现析构错误 双方手里都拿着对方的引用原来是二 后面变成一

shared_ptr 和 weak_ptr 都继承一个 基类 基类里面有两个成员变量(一个强指针计数器, 一个是弱指针计数器)

  • 强指针的构造 析构 赋值 拷贝构造下 计数器的变化

  • 弱指针的构造 析构 赋值 拷贝构造下 计数器的变化

  • 弱指针提升为强指针时 计数器变化

构造时 uses = 1 weaks = 1 当shared_ptr 加一uses 加一 weaks不变 当weak_ptr出现 uses不变 weaks加一

#include<iostream>
#include<algorithm>
#include<memory>
using namespace std;


class Cperson;
class CSon;

class Cperson {
public:
    Cperson() {}
    void Set(shared_ptr<CSon> pSon) {
        m_pSon = pSon;
    }
    ~Cperson() {
        cout <<"ppp" << endl;
    }
    shared_ptr<CSon> m_pSon; // 把其中一个改为weak_ptr打破闭环   让引用计数不变还是1进行减就变成零
};

class CSon {
public:
    CSon() {}
    void Set(shared_ptr<Cperson> parent) {
        m_parent = parent;
    }
    shared_ptr<Cperson> m_parent;
    ~CSon() {
        cout << "sss" <<endl;
    }

};


void test() {
    {
        shared_ptr<Cperson> p(new Cperson());
        shared_ptr<CSon> s(new CSon());
        p->Set(s);
        s->Set(p);
        cout << "p :" << p.use_count() <<endl;
        cout << "s :" << s.use_count() << endl;
    }
}

int main() {
    test();
}

此时不会执行析构函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值