在模拟my_share_ptr之前,我们深入区分一下,拷贝构造和移动构造,普通赋值和移动赋值的区别。
拷贝构造和移动构造的区别:
拷贝构造采用的方式是:将一个对象中指针所指的所有属性复制给被拷贝的对象。为了防止出现内存泄漏,需要被拷贝对象,重新申请一片堆空来存放所指之物。 移动构造是一个对象中的指针所指转移给被移动对象。因此需要将前者对他所拥有的数据的拥有权释放。
移动赋值和普通赋值的区别:
普通赋值:如 obja = base,是是将base中的指针所指赋值一份给obja。 移动就是直接转移给obja,base对资源的拥有权释放。
总结:
其实c11新引入的移动赋值和移动构造都是"右值引用"的概念的产生而产生,实际针对的是对对资源和系统内部资源进行转移引入的引入的一个新的概念。(实现的是资源的转移)
unique_ptr和share_ptr的区别:
unique_ptr(唯一性)智能指针,一次只能指向一个对象。 share_ptr(共享性)智能指针,多个指针可以指向同一个对象。 但是必须记录有多少个指针指向了同一个对象。
int main(void)
{
std::shared_ptr<Object> sp1(new Object(10));
return 0;
}
当两个指针同时指向同一个对象时,那么指向的引用计数就会加一。
int main(void)
{
std::shared_ptr<Object> sp1(new Object(10));
std::shared_ptr<Object> sp2(sp1);
return 0;
}
hared_ptr提供了两个函数来检查其共享的引用计数值,分别是unique()和use_count()。 use_count()函数,该函数返回当前指针的引用计数值。值得注意的是use_count()函数可能效率很低,应该只把它用于测试或调试。 unique()函数用来测试该shared_ptr是否是原始指针唯一拥有者,也就是use_count()的返回值为1时返回true,否则返回false。
std::shared_ptr<Object> sp1 = std::make_shared<Object>(10);
std::shared_ptr<Object> sp2(new Object(10));
cout << sp1.use_count() << endl;
cout << sp2.unique() << endl;
sp2(new Object(10));和std::make_shared(20);的区别
std::shared_ptr<Object> sp2(new Object(10));
std::shared_ptr<Object> sp1 = std::make_shared<Object>(20);
区别:
第一种,需要构建两次对象,所以就要析构两次 第二种, 只创建一次对象,只析构一次。Object完成初始化,op2直接指向既可以。
模拟my_share_ptr
删除单个对象
template<class _Ty>
class MyDeletor
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
删除一组对象template
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete[]ptr;
}
}
};
引用计数类
template<typename _Ty>
class RefCnt
{
private:
_Ty* mptr;
int ref;
public:
RefCnt(_Ty* p = nullptr) : mptr(p), ref(mptr != nullptr)
{
}
~RefCnt() {}
};
指向一个对象的my_share_ptr
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);
}
}
private:
RefCnt<_Ty>* ptr;
_Dx mDeletor;
};
拷贝构造:
由于是共享型智能指针,所以会让多个指针指向同一个对象,因此判断智能指针对象中ptr指针是否为空,如果不为空,对ptr->ref+1
my_share_ptr(const my_share_ptr& _Y):ptr(_Y.ptr)
{
if (ptr != NULL)
{
ptr->ref += 1;
}
}
移动构造
- 移动构造相当于直接操作sp1的值(sp1被做右值),直接将sp1的值给ptr
- 将sp1的中指针的指向置为空。(就是将sp1的资源转移给sp2)
my_share_ptr(my_share_ptr&& _Y):ptr(_Y.ptr)
{
_Y.ptr = NULL;
}
普通赋值(重点)
完成赋值需要满足的条件:
if (this == &_Y || this->ptr == _Y.ptr) return *this;
my_share_ptr<Object>op1(new Object(5));
my_share_ptr<Object>op2(new Object(5));
op1 = op1;
op1 = op2;
2.if (ptr != NULL && --ptr->ref == 0)
my_share_ptr<Object>op1(new Object(5));
my_share_ptr<Object>op2(new Object(10));
op2 = op1;
- op1 = op2 完成,需要对ptr->ref+1,因为有两个指针同时指向op2中的指针所指的对象。
my_share_ptr& operator=(const my_share_ptr& _Y)
{
if (this == &_Y || this->ptr == _Y.ptr) return *this;
if (ptr != NULL && --ptr->ref == 0)
{
mDeletor(ptr);
}
ptr = _Y.ptr;
if (ptr != nullptr)
{
ptr->ref += 1;
}
return *this;
}
int main()
{
my_share_ptr<Object>op1;
my_share_ptr<Obbject>op2(new Object(10));
op2 = op1;
}
int main()
{
my_unique_ptr<Object>sp1(new Object(5));
my_unique_ptr<Object>sp2;
my_unique_ptr<Object>sp3;
my_unique_ptr<Object>sp1(new Object(10));
sp2 = sp3;
sp2 = sp1;
sp1 = sp3;
sp2 = sp4;
}
两个共享性指针指向同一个对象。
移动赋值(重点)
my_share_ptr& operator =(my_share_ptr&& _Y)
{
if (this == &_Y) return *this;
if (ptr == _Y.ptr && ptr != NULL && _Y.ptr != NULL)
{
ptr->ref -= 1;
_Y.ptr = NULL;
return *this;
}
if (ptr != NULL && --ptr->ref == 0)
{
MDeletor(ptr);
}
ptr = _Y.ptr;
_Y.ptr = NULL;
return *this;
}
int main()
{
my_unique_ptr<Object>sp1(new Object(5));
my_unique_ptr<Object>sp3(sp1);
my_unique_ptr<Object>sp2(sp1);
sp1 = std::move(sp2);
}
reset()函数
1.判断当前指针是否为空,并且指向一个对象。如果符合,调用删除器,解绑。 2.当前指针重新向堆区引用计数的结构,该结构的指着指向参数类的对象。
void reset(_Ty* p = nullptr)
{
if (this->ptr != nullptr && --this->ptr->ref == 0)
{
mDeletor(ptr);
}
ptr = new RefCnt<_Ty>(p);
}
析构函数
1.判断当前ptr是否为空,以及是否指向一个对象。满足条件,调用删除器,删除ptr指向的引用计数对象的mptr指针指向的对象。在删除ptr。 2.将ptr置为空。
~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();
}
获取当前引用计数的个数
size_t use_count() const
{
if (this->ptr == nullptr) return 0;
return this->ptr->ref;
}
交换资源
void swap(my_shared_ptr& r)
{
std::swap(this->ptr, r.ptr);
}
指向一组对象的my_share_ptr
特点: 1.删除一组对象是,对于删除操作,我们都要先删除,当前指针所指的引用计数对象中的指针mptr所指。 2.在删除ptr指针。多个指针指向一组对象。 改下如下:
if (ptr != nullptr && --ptr->ref == 0)
{
mDeletor(ptr->mptr);
delete ptr;
}
提供索引访问:
_Ty& operator[](const int idx) const
{
return ptr->mptr[idx];
}
完整代码
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* p = nullptr) :mptr(p), ref(mptr != nullptr) {}
~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;
}
}
my_shared_ptr(my_shared_ptr&& _Y) :ptr(_Y.ptr)
{
_Y.ptr = nullptr;
}
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 != NULL && --ptr->ref == 0)
{
mDeletor(ptr);
}
ptr = _Y.ptr;
if (ptr != nullptr)
{
ptr->ref += 1;
}
return *this;
}
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 (this->ptr != nullptr && --ptr->ref == 0)
{
mDeletor(ptr);
}
ptr = _Y.ptr;
_Y.ptr = nullptr;
return *this;
}
void reset(_Ty* p = nullptr)
{
if (this->ptr != nullptr && --this->ptr->ref == 0)
{
mDeletor(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();
}
size_t use_count() const
{
if (this->ptr == nullptr) return 0;
return this->ptr->ref;
}
void swap(my_shared_ptr& r)
{
std::swap(this->ptr, r.ptr);
}
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;
}
}
my_shared_ptr(my_shared_ptr&& _Y) :ptr(_Y.ptr)
{
_Y.ptr = nullptr;
}
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 != NULL && --ptr->ref == 0)
{
mDeletor(ptr->mptr);
delete ptr;
}
ptr = _Y.ptr;
if (ptr != nullptr)
{
ptr->ref += 1;
}
return *this;
}
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 (this->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();
}
size_t use_count() const
{
if (this->ptr == nullptr) return 0;
return this->ptr->ref;
}
void swap(my_shared_ptr& r)
{
std::swap(this->ptr, r.ptr);
}
_Ty& operator[](const int idx) const
{
return ptr->mptr[idx];
}
private:
RefCnt<_Ty>* ptr;
_Dx mDeletor;
};
|