目录
1.基础函数的简单代码实现
#pragma once
#ifndef MY_SHARED_PTR_H
#define MY_SHARED_PTR_H
//辅助类--default——delete
//删除器
template<class _Ty>
class MyDeletor
{
public:
MyDeletor() {}
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
delete ptr;
}
};
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;//明确的告知有构造函数
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
delete[] ptr;
}
};
template<class _Ty>
class RefCnt
{
public:
_Ty* mptr;//指向对象
int ref;//引用技术
public:
RefCnt(_Ty* ptr = nullptr) :mptr(ptr), ref(mptr != nullptr)
{
//ref = mptr == nullptr ? 0 : 1;
}
~RefCnt() {}
};
//默认删除器只删除一个对象
template<class _Ty, class _Dx=MyDeletor<_Ty>>//对象,删除器
class my_shared_ptr
{
public:
my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr)
{
if (p != nullptr)
{
ptr = new RefCnt(p);
}
}
my_shared_ptr(const my_shared_ptr& _Y) :ptr(_Y.ptr)
{
if (ptr != nullptr) {
ptr->ref += 1;
}
}
//检查是否有关联的管理对象
operator bool()const { return ptr != nullptr; }
//赋值语句
my_shared_ptr& operator=(const my_shared_ptr& _Y)
{
if (this == &_Y || this->ptr == _Y.ptr) return *this;
if (ptr != nullptr && --ptr->ref == 0) {
mDeletor(ptr->mptr);
delete ptr;
}
ptr = _Y.ptr;
if (ptr != nullptr)
{
ptr->ref += 1;
}
return *this;
}
//c11中新增的
//移动构造函数
my_shared_ptr(my_shared_ptr&& _Y) :ptr(_Y.ptr)
{
_Y.ptr = nullptr;
}
//移动赋值(自己的资源移动过去)
my_shared_ptr& operator=(my_shared_ptr&& _Y)
{
if (this == &_Y) return *this;
if (this->ptr == _Y.ptr && this->ptr != nullptr && _Y.ptr != nullptr)
{
this->ptr->ref -= 1;
_Y.ptr = nullptr;
return *this;
}
if (ptr != nullptr && --ptr->ref == 0)
{
mDeletor(ptr->mptr);
delete ptr;
}
ptr = _Y.ptr;
_Y.ptr = nullptr;
return *this;
}
void* reset(_Ty *p= nullptr)
{
if (this->ptr != nullptr && --this->ptr->ref == 0)
{
mDeletor(ptr->mptr);
delete ptr;
}
ptr = new RefCnt<_Ty>(p);
}
~my_shared_ptr()
{
if (this->ptr != nullptr && --this->ptr->ref == 0)
{
mDeletor(ptr->mptr);
delete ptr;
}
ptr = nullptr;
}
//返回存储的指针
_Ty* get()const { return ptr->mptr; }
//解引用存储的指针
_Ty& operator*()const
{
return *get();
}
_Ty* operator->()const
{
return get();
}
//返回share_ptr所指对象的引用计数
size_t use_count()const
{
if (this->ptr == nullptr) return 0;
return this->ptr->ref;
}
//交换管理的对象
void swap(my_shared_ptr& _Y)
{
std::swap(this->ptr, _Y.ptr);
}
_Ty& operator[](const int idx)const
{
}
private:
RefCnt<_Ty>* ptr;
_Dx mDeletor;
};
template<class _Ty,class _Dx>
class my_shared_ptr<_Ty[],_Dx>
{
public:
my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr)
{
if (p != nullptr)
{
ptr = new RefCnt(p);
}
}
my_shared_ptr(const my_shared_ptr& _Y) :ptr(_Y.ptr)
{
if (ptr != nullptr) {
ptr->ref += 1;
}
}
//检查是否有关联的管理对象
operator bool()const { return ptr != nullptr; }
//赋值语句
my_shared_ptr& operator=(const my_shared_ptr& _Y)
{
if (this == &_Y || this->ptr == _Y.ptr) return *this;
if (ptr != nullptr && --ptr->ref == 0) {
mDeletor(ptr->mptr);
delete ptr;
}
ptr = _Y.ptr;
if (ptr != nullptr)
{
ptr->ref += 1;
}
return *this;
}
//c11中新增的
//移动构造函数
my_shared_ptr(my_shared_ptr&& _Y) :ptr(_Y.ptr)
{
_Y.ptr = nullptr;
}
//移动赋值(自己的资源移动过去)
my_shared_ptr& operator=(my_shared_ptr&& _Y)
{
if (this == &_Y) return *this;
if (this->ptr == _Y.ptr && this->ptr != nullptr && _Y.ptr != nullptr)
{
this->ptr->ref -= 1;
_Y.ptr = nullptr;
return *this;
}
if (ptr != nullptr && --ptr->ref == 0) {
mDeletor(ptr->mptr);
delete ptr;
}
ptr = _Y.ptr;
_Y.ptr = nullptr;
return *this;
}
void* reset(_Ty *p= nullptr)
{
if (this->ptr != nullptr && --this->ptr->ref == 0)
{
mDeletor(ptr->mptr);
delete ptr;
}
ptr = new RefCnt<_Ty>(p);
}
~my_shared_ptr()
{
if (this->ptr != nullptr && --this->ptr->ref == 0)
{
mDeletor(ptr->mptr);
delete ptr;
}
ptr = nullptr;
}
//返回存储的指针
_Ty* get()const { return ptr->mptr; }
//解引用存储的指针
_Ty& operator*()const
{
return *get();
}
_Ty* operator->()const
{
return get();
}
//返回share_ptr所指对象的引用计数
size_t use_count()const
{
if (this->ptr == nullptr) return 0;
return this->ptr->ref;
}
//交换管理的对象
void swap(my_shared_ptr& _Y)
{
std::swap(this->ptr, _Y.ptr);
}
_Ty& operator[](const int idx)const
{
return ptr->mptr[idx];
}
private:
RefCnt<_Ty>* ptr;
_Dx mDeletor;
};
#endif
2.计数时产生的不安全问题
因为是共享型指针,在多线程中会出现问题--在计数时不能用int类型(不安全)引入原子类型计数
#include<atomic>--
std::atomic_int ref;//原子类型
3.循环引用问题以及解决方法
(1)循环引用会造成内存泄漏
(2)解决方法--引入weak_ptr指针
例子:
template <typename T>
class A{
public:
A(const T &x):_val(x), _Pre(nullptr), _Next(nullptr){
}
shared_ptr<A<T>> _Pre;//weak_ptr
shared_ptr<A<T>> _Next;//weak_ptr
T _val;
};
void func(){
shared_ptr<A<int>> s1(new A<int>(1));
shared_ptr<A<int>> s2(new A<int>(2));
s1->_Next = s2;
s2->_Pre = s1;
}
int main(){
fun();
return 0;
}
例子中会造成循环引用问题,将shared_ptr换成weak_ptr可以解决循环引用的问题
4.make_shared
make_shared和shared_ptr<Object> new(Object(10)) 的优缺点
优点:
(1).只开辟一次堆区,减少堆区的开辟和释放次数
(2).cache块中很快的命中它,空间局部性,对对象前后的内存块都要访问---对象和引用技术在一个空间(命中率提高)---原因:程序自动的把管理对象占得内存和计数器占在对上的内存作为整体来管理
(3).调用次序不定的情况下,仍然对object对象处于管理阶段
例:
class Object
{
private:
int value;
public:
Object(int x = 0) :value(x) { cout << "Object" << endl; }
~Object() { cout << "~Object" << endl; }
void Print()const { cout<<value<<endl; }
};
double couldThrowException()
{
throw int(10);
return 12.23;
}
void doSomething(std::shared_ptr<Object> pt, double d)
{
}
void fun()
{
try
{
//doSomething(std::shared_ptr<Object>(new Object(10)), couldThrowException());
//即使此函数返回抛出异常-make_shared依然对对象处于管理阶段
doSomething(std::make_shared<Object>(10), couldThrowException());
}
catch (...)
{
cout << "catch(...)" << endl;
}
}
int main()
{
fun();
return 0;
}
缺点:
程序自动的把管理对象占得内存和计数器占在对上的内存作为整体来管理,--即使被管理的对象析构了,空间还在,内存没被归还,等着所有的weak_ptr都被清除后和计数器所占用的内存一起北归还 ,如果对象有点大,意味着一个相当大的内存被无意义的锁了一段时间