Open bosthhe1 opened 1 year ago
智能指针有四种模式,第一种auto_prt - 管理权转移,不建议使用 其他三种为:unique_ptr,share_prt,weak_ptr 下面是对三种不同模式进行讲解
unique_ptr是比较简单粗暴,使用的是直接将拷贝构造和赋值都删除,不使用拷贝构造和赋值,这样可以防止拷贝。
template<class T>
struct Deletefile
{
void operator()(T* ptr)//自己手动配置回收
{
delete ptr;
}
};
template<class T,class Deletefile = Deletefile<T>>
class unique_ptr
{
private:
unique_ptr(const unique_ptr<T>& Sef) = delete;
unique_ptr<T> operator=(const unique_ptr<T>& Sef)= delete;
public:
unique_ptr(T* ptr)
:_ptr(ptr)
{}
~unique_ptr()
{
Deletefile()(_prt);
}
private:
T* _prt;
};
void func1()
{
int* a = new int;
int* b = new int;
hxh::unique_ptr<int> a1(a);//将a的内容交给a1管理,这样出了作用域就可以直接析构,不用手动调用delete
hxh::unique_ptr<int> b1(b);
throw string("内存泄露");
}
share_ptr的使用场景是多个指针都会使用这个对象,这样会造成多次析构的问题,可以使用引用计数的方式防止多次释放,
template<class T>
class shared_ptr
{
public:
shared_ptr(T* num =nullptr)
:_ptr(num)
, _CountSum(new int(1))
, mtx(new mutex)
{}
shared_ptr(shared_ptr<T>& sp)
:_ptr(sp._ptr)
{
mtx = sp.mtx;
_CountSum = sp._CountSum;
mtx->lock();
(*_CountSum)++;
mtx->unlock();
}
T* operator->()
{
return _ptr;
}
T& operator*()
{
return *_ptr;
}
shared_ptr<T>& operator=(const shared_ptr<T>& sp)
{
if (sp._ptr != _ptr)
{
mtx->lock();
(*_CountSum)--;
if (*_CountSum == 0)
{
delete _ptr;
delete _CountSum;
mtx->unlock();
delete mtx;
}
else
{
mtx->unlock();
}
mtx = sp.mtx;
_ptr = sp._ptr;
_CountSum = sp._CountSum;
mtx->lock();
(*_CountSum)++;
mtx->unlock();
}
return *this;
}
~shared_ptr()
{
mtx->lock();
(*_CountSum)--;
if (*_CountSum == 0)
{
delete _ptr;//share_prt 和unqiue_ptr的回收机制不一样,因为share_ptr是多个参数需要回收,所以系统的回收机制是传参数进行回收,而不是模板
delete _CountSum;
}
mtx->unlock();
}
private:
T* _ptr;
int* _CountSum;
mutex* mtx;
};
struct Data
{
int year;
int month;
int day;
Data()
:year(1)
,month(1)
,day(1)
{}
};
void func3(hxh::shared_ptr<Data> a)
{
for (int i = 0; i < 10000; i++)
{
hxh::shared_ptr<Data> copy(a);
copy->year++;
copy->month++;
copy->day++;
}
}
int main()
{
hxh::shared_ptr<Data> a(new Data());
thread td(func3, std::ref(a));
thread td1(func3, std::ref(a));
td.join();
td1.join();
cout << a->year << " " << a->month << " " << a->day << endl;
return 0;
}
可以看出shared_ptr中的锁只对shared_ptr类的内部有用,出了外部还需要自己加锁
void func3(hxh::shared_ptr<Data>& a,mutex& mtx)
{
for (int i = 0; i < 10000; i++)
{
hxh::shared_ptr<Data> copy(a);
unique_lock<mutex> lk(mtx);
copy->year++;
copy->month++;
copy->day++;
}
}
关于shared_ptr的垃圾回收的伪代码
class A
{
public:
A()
:a(new int)
,b(new int)
{}
~A()
{
delete a;
delete b;
}
int* a;
int* b;
};
struct deletefileA
{
void operator()(A* a)
{
cout << "delete" << endl;
delete a->a;
delete a->b;
}
};
int main()
{
{
A* a(new A());
std::shared_ptr<A> sp(a,deletefileA());//shared_ptr传入垃圾回收的匿名对象对底层进行构造一个回收机制的对象,然后实现回收
}
return 0;
}
shared_ptr会出现循环引用的问题
struct ListNode
{
int val;
hxh::shared_ptr<ListNode> next;
hxh::shared_ptr<ListNode> prev;
~ListNode(){ cout << "~ListNode()" << endl; }
};
}
int main()
{
{
hxh::shared_ptr<hxh::ListNode> sp1(new hxh::ListNode);
hxh::shared_ptr<hxh::ListNode> sp2(new hxh::ListNode);
sp1->next = sp2;
sp2->prev = sp1;
}
return 0;
}
我们看到当出了作用域却没有调析构函数 我们看到sp1要想析构那么就需要sp2析构,sp2析构那么就要sp1析构,这样构成了一份死循环
weak_ptr可以解决循环引用的问题,原理就是引用之后不用计数++
struct ListNode
{
int val;
std::weak_ptr<ListNode> next;//注意这里是weak_ptr,下面依然是shared_ptr,依然可以赋值,应该weak_ptr为父类,shared_ptr为子类
std::weak_ptr<ListNode> prev;
~ListNode(){ cout << "~ListNode()" << endl; }
};
int main()
{
{
std::shared_ptr<ListNode> sp1(new ListNode);
std::shared_ptr<ListNode> sp2(new ListNode);
sp1->next = sp2;//weak_ptr这里可以直接引用shared_ptr
sp2->prev = sp1;
}
return 0;
}
智能指针和异常也有很大关联,智能指针的原理是RAII(利用对象的生命周期来控制进程资源),这个和guard_mutx锁很像,但是也增加其他的一些特点,如定制垃圾回收器 //一下就是造成了内存的问题,a,b在堆山开辟空间,但是没有释放