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();
}
此时不会执行析构函数