前言
在上篇文章中说到,智能指针unique_ptr的删除器有不同的特化版本,本文将模拟实现unique_ptr和它的辅助类 删除器。
文章目录
一、删除器
1.泛化版本的删除器
在这个模板类中,实现其删除仿函数,实现的是delete ptr,意思就是可以删除单独的堆区对象。
template<class _Ty>
class MyDeletor
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
2. 部分特化版本的删除器
这个删除器的参数特化了一个类型加[ ],且在实现时使用的delete[] ptr,意思是可以接收一组对象,析构堆区的一组对象。
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete[]ptr;
}
}
};
二、实现my_unique_ptr
(一) 泛化版本——指向单独对象的智能指针
- 首先,模板给出两个参数,一个是要指向的对象类型,另一个是删除器类型,这个删除器是泛化版本的删除器。
- 私有成员有两个,一个是指针,一个是删除器成员。
- 模拟unique_ptr的特性,不能拷贝构造和赋值构造,所以将这两个函数删除。
- 在析构函数中,如果指针不为nullptr,则调用删除器,并将指针指向nullptr。
// class unique_ptr
template<class _Ty, class _Dx = MyDeletor<_Ty> >
class my_unique_ptr
{
public:
using pointer = _Ty*; //typedef _Ty* pointer;
using element_type = _Ty; //typedef _Ty element_type;
using delete_type = _Dx; //typedef _Dx delete_type;
private:
_Ty* _Ptr;
_Dx _myDeletor;
public:
my_unique_ptr(const my_unique_ptr&) = delete;
my_unique_ptr& operator=(const my_unique_ptr&) = delete;
my_unique_ptr(pointer _P = nullptr) :_Ptr(_P) { cout << "my_unique_ptr: " << this << endl; }
~my_unique_ptr()
{
if (_Ptr != nullptr)
{
_myDeletor(_Ptr);
_Ptr = nullptr;
}
cout << "~my_unique_ptr: " << this << endl;
}
观察器
1.获得用于析构被管理对象的删除器
两个版本:普通的和常性的
_Dx& get_deletor()
{
return _myDeletor;
}
const _Dx& get_deletor() const
{
return _myDeletor;
}
2. 获得当前指针
pointer get() const
{
return _Ptr;
}
3.重载bool运算符
operator bool() const
{
return _Ptr != nullptr;
}
有了这个方法,就可以在各种控制语句中使用该指针。
示例:
int main(void)
{
my_unique_ptr<int> op(new int(10));
if (op) {
//
}
op != false;
}
4.重载解引用和指向符
重载解引用符,为了获得当前指针所指向的对象;
重载指向符,是为了获得指针本身。
_Ty& operator*() const
{
return *_Ptr;
}
pointer operator->() const
{
return &**this;// _Ptr;
}
修改器
5.释放资源函数(释放所有权)
即将资源转移给其他指针:再将自身指针置为空。
pointer release()
{
_Ty* old = _Ptr;
_Ptr = nullptr;
return old;
}
6.重置指向函数(替换被管理对象)
申请一个指针指向当前指针所指向的对象;
让当前指针指向函数传递进来的参数所指向的对象;
再(调用删除器)将原来所指的对象删除。
void reset(pointer _P = nullptr)
{
pointer old = _Ptr;
_Ptr = _P;
if (old != nullptr)
{
_myDeletor(old);
// get_deletor()(old);
}
}
7.交换资源的函数
直接调用系统提供的swap函数
void swap(my_unique_ptr _Y)
{
std::swap(_Ptr, _Y._Ptr);
std::swap(_myDeletor, _Y._myDeletor);
}
特殊的成员函数
8.移动构造和移动赋值
移动构造:将资源转移给this当前的指针。
my_unique_ptr(my_unique_ptr&& _Y)
{
_Ptr = _Y._Ptr;
_Y._Ptr = nullptr;
cout << " move copy my_unique_ptr : " << this << endl;
}
移动赋值:同样是完成资源的转移
流程:
- 如果this指针与参数相同,则不执行,直接返回this
- 查看当前指针指向是否为空,不为空则调用删除器删除
- 将参数的资源转移给this的_Ptr,再将参数的_Ptr置为空。
- 返回this指针所指之物。
my_unique_ptr& operator=(my_unique_ptr&& _Y)
{
if (this == &_Y) return *this;
if (_Ptr != nullptr) { _myDeletor(_Ptr); }
_Ptr = _Y._Ptr;
_Y._Ptr = nullptr;
cout << " move opertor=: " << endl;
return *this;
}
实际上,上述代码可以利用已实现的函数来完成
my_unique_ptr& operator=(my_unique_ptr&& _Y)
{
if (this == &_Y) return *this;
reset(_Y.release());
cout << " move opertor=: " << endl;
return *this;
}
(二)部分特化版本——指向一组对象的智能指针
特化版本除了模板参数有变化,其他内容和泛化版本一致。
// class unique_ptr array
template<class _Ty, class _Dx >
class my_unique_ptr<_Ty[], _Dx>
{
public:
using pointer = _Ty*; //typedef _Ty* pointer;
using element_type = _Ty; //typedef _Ty element_type;
using delete_type = _Dx; //typedef _Dx delete_type;
private:
_Ty* _Ptr;
_Dx _myDeletor;
}
提供到被管理数组的有索引访问
_Ty& operator[](size_t _Idx) const
{
return _Ptr[_Idx];
}
(三)创建一个管理新对象的独占指针
C++14引入make_unique<>
构造的指针可以指向 多个参数的对象,再构造时传入的参数可变。
template<class _Ty, class ..._Type>
my_unique_ptr<_Ty> my_make_unique(_Type&& ... _arys)
{
return my_unique_ptr<_Ty>(new _Ty(_arys...));
}
三、完整代码
template<typename _Ty>
class myDeletor
{
public:
myDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
template<typename _Ty>
class myDeletor<_Ty[]>
{
public:
myDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete[]ptr;
}
}
};
// my_unique_ptr
template<typename _Ty, typename _Dx = myDeletor<_Ty> >
class my_unique_ptr
{
public:
using pointer = _Ty*;
using element_type = _Ty;
using delete_type = _Dx;
private:
pointer _Ptr;
delete_type _myDeletor;
public:
my_unique_ptr(const my_unique_ptr& _Y) = delete;
my_unique_ptr operator =(const my_unique_ptr& _Y) = delete;
my_unique_ptr(pointer _P = nullptr)
: _Ptr(_P)
{
cout << "my_unique_ptr: " << this << endl;
}
~my_unique_ptr() {
if (_Ptr != nullptr) {
_myDeletor(_Ptr);
_Ptr = nullptr;
}
cout << "~my_unique_ptr: " << this << endl;
}
_Dx& get_deletor() {
return _myDeletor;
}
const _Dx& get_deletor() const {
return _myDeletor;
}
pointer get_pointer() const {
return _Ptr;
}
operator bool() {
return _Ptr != nullptr;
}
_Ty& operator*() const {
return *_Ptr;
}
pointer operator->() const {
return &**this;
}
pointer release() {
pointer old = _Ptr;
_Ptr = nullptr;
return old;
}
void reset(pointer _P = nullptr) {
pointer old = _Ptr;
_Ptr = _P;
if (old != nullptr) {
_myDeletor(old);
// get_deletor()(old);
}
}
void Swap(my_unique_ptr _Y) {
std::swap(_Ptr, _Y._Ptr);
std::swap(_myDeletor, _Y._myDeletor);
}
my_unique_ptr(my_unique_ptr&& _Y) {
_Ptr = _Y._Ptr;
_Y = nullptr;
}
my_unique_ptr& operator=(my_unique_ptr&& _Y) {
if (this == &_Y) {
return *this;
}
reset(_Y.release());
return *this;
}
};
// array
template<typename _Ty, typename _Dx>
class my_unique_ptr<_Ty[], _Dx>
{
public:
using pointer = _Ty*;
using element_type = _Ty;
using delete_type = _Dx;
private:
pointer _Ptr;
delete_type _myDeletor;
public:
my_unique_ptr(const my_unique_ptr& _Y) = delete;
my_unique_ptr operator =(const my_unique_ptr& _Y) = delete;
my_unique_ptr(pointer _P = nullptr)
: _Ptr(_P)
{
cout << "my_unique_ptr: " << this << endl;
}
~my_unique_ptr() {
if (_Ptr != nullptr) {
_myDeletor(_Ptr);
_Ptr = nullptr;
}
cout << "~my_unique_ptr: " << this << endl;
}
_Dx& get_deletor() {
return _myDeletor;
}
const _Dx& get_deletor() const {
return _myDeletor;
}
pointer get_pointer() const {
return _Ptr;
}
operator bool() {
return _Ptr != nullptr;
}
_Ty& operator*() const {
return *_Ptr;
}
pointer operator->() const {
return &**this;
}
pointer release() {
pointer old = _Ptr;
_Ptr = nullptr;
return old;
}
void reset(pointer _P = nullptr) {
pointer old = _Ptr;
_Ptr = _P;
if (old != nullptr) {
_myDeletor(old);
// get_deletor()(old);
}
}
void Swap(my_unique_ptr _Y) {
std::swap(_Ptr, _Y._Ptr);
std::swap(_myDeletor, _Y._myDeletor);
}
my_unique_ptr(my_unique_ptr&& _Y) {
_Ptr = _Y._Ptr;
_Y = nullptr;
}
my_unique_ptr& operator=(my_unique_ptr&& _Y) {
if (this == &_Y) {
return *this;
}
reset(_Y.release());
return *this;
}
_Ty& operator[](size_t _Idx) const {
return _Ptr[_Idx];
}
};
template<typename _Ty, typename ... _Type>
my_unique_ptr<_Ty> my_make_unique(_Type&& ... _args)
{
return my_unique_ptr<_Ty>(new _Ty(_args...));
}