文章目录
C++中的辅助类型
default_delete (C++11)
MyDeletor() = default;给了一个默认构造函数
Object(const Object &) = delete //属于C11新添加的功能。告诉编译我要做什么
template<class _Ty>
class MyDeletor
{
public:
MyDeletor() = default;//表示默认构造
void operator()(_Ty * ptr)const
{
if (ptr != NULL)
{
delete ptr;
}
}
};
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;//表示默认构造
void operator()(_Ty* ptr)const
{
if (ptr != NULL)
{
delete []ptr;
}
}
};
模拟unique_ptr(泛化版本)----对单一对象的处理
- 模板中有两个参数,一个是指向对象类型,一个是删除器类型。
- 私有成员一个是指针,一个是删除器成员。
- 模拟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(pointer _P = NULL) :_Ptr(_P) {}
my_unique_ptr(const my_unique_ptr& ptr) = delete; //因此不能进行赋值操作
my_unique_ptr& operator=(const my_unique_ptr& ptr) = delete;//也不能进行=号操作
~my_unique_ptr()
{
if (_Ptr != NULL)
{
_myDeletor(Ptr);//局部对象加()调用的是void operator()(Ty* ptr)const
_Ptr = NULL;
}
}
};
观察器
删除器
用于析构被管理对象的删除器(普通和常性)
_Dx& get_deletor()
{
return _myDeletor;
}
_Dx& get_deletor()const
{
return _myDeletor;
}
*和->重载(引用和指向)
_Ty& operator*()const
{
return *_Ptr;
}
_Ty operator->()
{
return _Ptr;//&**this
}
获取当前指针
pointer get()
{
return _Ptr;
}
重载bool运算符
operator bool()const
{
return _Ptr != NULL;
}
};
int main()
{
my_unique_ptr<int> op;
my_unique_ptr<int> op2(new int(10));
if (op) {}//if(op.operator bool())就可以判断真假
if (op2) {}
op2 != nullptr; //不可以比较,因为只能指针和指针比较,(nullptr相当于空指针)
//op2是一个bool类型
op2 != false;//是可以的
}
修改器
释放当前资源
将资源转移给old,然后自身指针置为空
pointer release()
{
_Ty* old = _Ptr;
_Ptr = NULL;
return old;
}
重置指针的指向
old指向当前指针所指对象(如果不这样做,会导致指针所指的对象不能被删除)
当前指针指向新的指针所指的对象
在调用删除器删掉old
void reset(pointer _p = NULL)//重置
{
pointer old = _Ptr;//防止该空间无法被释放
_Ptr = _p;
if (old != NULL)
{
//_myDeletor(old);
get_deleter()(old);
}
}
是否使用内联,取决于系统需不需要节省开栈清栈的时间。
移动构造
my_unique_ptr(my_unique_ptr&& _Y)
{
Ptr = _Y._Ptr;
_Y._Ptr = NULL;
}
移动赋值
my_unique_ptr& operator=(my_unique_ptr&& _Y)
{
if (this == _Y) return *this;
reset(_Y.release());
return *this;
}
交换
void swap(my_unique_ptr _Y)
{
std::swap(_Ptr, _Y._Ptr);
std::swap(_myDeletor, _Y._myDeletor);
}
部分特化版本:
template<class _Ty, class _Dx = MyDeletor<_Ty> >
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;
public:
my_unique_ptr(pointer _P = NULL) :_Ptr(p) {}
my_unique_ptr(const my_unique_ptr& ptr) = delete; //因此不能进行赋值操作
my_unique_ptr& operator=(const my_unique_ptr& ptr) = delete;//也不能进行=号操作
~my_unique_ptr()
{
if (_Ptr != NULL)
{
_myDeletor(Ptr);//局部对象加()调用的是void operator()(Ty* ptr)const
_Ptr = NULL;
}
}
};
提供到被管理数组的有索引访问(数组版本)
_Ty& operator[](size_t _Idx)const
{
return _Ptr[_Idx];
}
可变参数类型
template<class _Ty a>
template<class _Ty a ,class _Uy b>
template<class _Ty a ,class _Uy b,class Ty c>
fun(12)
fun(12,12)
fun(12,12,12)
fun(12,12,12,12);就没有可适用的模板了。
而可变参数模板类型正是来解决这个问题。
template<class _Ty...>
构造的指针可以指向多个参数的对象,再构造时传入的参数可变。
template<class _Ty,class ..._Type>
my_unique_ptr<_Ty>my_make_unique(_Type&& ..._arrys)
{
return my_unique_ptr<_Ty>(new_Ty(arys...));
}
int main()
{
my_unique_ptr<Object> op1 = my_make_unique<Object>();//调动的是默认构造
my_unique_ptr<Object> op2 = my_make_unique<Object>(1); //可变参数
my_unique_ptr<Object> op3 = my_make_unique<Object>(1, 2, 3);
}
测试:
测试1:返回具名对象,会调用移动构造创建将亡值对象。
my_unique_ptr<Object> fun()
{
my_unique_ptr<Object> opa(new Object(10));
return opa;//此时调用的移动构造函数,构建将亡值,来获取opa对象的内容
//函数结束opa就会被析构
}
//测试1
int main()
{
my_unique_ptr<Object>opb;
opb = fun();
}
1.调用调用my_unique_ptr创建opb对象,进fun()函数内,调用Object的构造函数创建不具名对象,并初始化
2.调用my_unique_ptr的构造函数创建opa对象,并指向不具名对象的地址
3.返回opa,调用移动构造,构建将亡值对象,指向opa指向的不具名对象地址。
4.程序结束,析构opa,返回到调用点
5.调用移动赋值,将将亡值对象保存的值传给opb,析构将亡值对象。
6.析构opb对象
测试2:如果使用右值引用返回:(不要这样做)
如下
my_unique_ptr<Object> &&fun()
{
my_unique_ptr<Object> opa(new Object(10));
return std::move(opa); //使用右值引用返回,将不具名对象转化具名对象,因此opa析构,右值引用只是一个别名,自然也访问不到opa所指的对象地址。
}
int main()
{
my_unique_ptr<Object>opb;
opb = fun();
}
测试三:直接返回不具名对象,不需要调用移动构造
my_unique_ptr<Object> funb() //可以输出,将不具名对象资源调用移动赋值直接给objb
{
return my_unique_ptr<Object> (new Object(5));
}
int main()
{
my_unique_ptr<Object>opb;
opb = fun();
}
1.调用调用my_unique_ptr创建opb对象,进fun()函数内,调用Object的构造函数创建不具名对象,并初始化
2.调用my_unique_ptr的构造函数创建不具名对象,并指向不具名对象的地址
3.返回不具名对象
4.调用移动赋值,将不具名对象保存的值传给opb,析构不具名对象
6.析构opb对象
注意:
不允许使用引用和右值引用,因为只要加引用,就不让不具名对象转换为具名对象,就不会按照移动赋值的方式将不具名对象指向的内容提交给objb。而是函数结束,便会析构掉,拿着它的别名,资源已经被释放,找不到了。
所以,不管在任何时候,都不要用引用或者右值引用返回一个不具名对象。
源码
泛化版本
template<class _Ty>
class MyDeletor
{
public:
MyDeletor() = default;//表示默认构造
void operator()(_Ty * ptr)const
{
if (ptr != NULL)
{
delete ptr;
}
}
};
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;//表示默认构造
void operator()(_Ty* ptr)const
{
if (ptr != NULL)
{
delete []ptr;
}
}
};
//模拟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(pointer _P = NULL) :_Ptr(_P) {}
my_unique_ptr(const my_unique_ptr& ptr) = delete; //因此不能进行赋值操作
my_unique_ptr& operator=(const my_unique_ptr& ptr) = delete;//也不能进行=号操作
~my_unique_ptr()
{
if (_Ptr != NULL)
{
_myDeletor(_Ptr);//局部对象加()调用的是void operator()(Ty* ptr)const
_Ptr = NULL;
}
}
my_unique_ptr(my_unique_ptr&& _Y)
{
_Ptr = _Y._Ptr;
_Y._Ptr = NULL;
}
my_unique_ptr& operator=(my_unique_ptr&& _Y)
{
if (this == &_Y) return *this;
reset(_Y.release());
return *this;
}
_Dx& get_deletor()
{
return _myDeletor;
}
_Dx& get_deletor()const
{
return _myDeletor;
}
_Ty& operator*()const
{
return *_Ptr;
}
_Ty operator->()
{
return _Ptr;//&**this
}
pointer get()
{
return _Ptr;
}
operator bool()const
{
return _Ptr != NULL;
}
pointer release()
{
_Ty* old = _Ptr;
_Ptr = NULL;
return old;
}
void reset(pointer _p = NULL)//重置
{
pointer old = _Ptr;
_Ptr = _p;
if (old != NULL)
{
//_myDeletor(old);
get_deletor()(old);
}
}
void swap(my_unique_ptr _Y)
{
std::swap(_Ptr, _Y._Ptr);
std::swap(_myDeletor, _Y._myDeletor);
}
};
//特化版本:访问一组对象
template<class _Ty, class _Dx = MyDeletor<_Ty> >
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;
public:
my_unique_ptr(pointer _P = NULL) :_Ptr(p) {}
my_unique_ptr(const my_unique_ptr& ptr) = delete; //因此不能进行赋值操作
my_unique_ptr& operator=(const my_unique_ptr& ptr) = delete;//也不能进行=号操作
~my_unique_ptr()
{
if (_Ptr != NULL)
{
_myDeletor(Ptr);//局部对象加()调用的是void operator()(Ty* ptr)const
_Ptr = NULL;
}
}
my_unique_ptr(my_unique_ptr&& _Y)
{
_Ptr = _Y._Ptr;
_Y._Ptr = NULL;
}
my_unique_ptr& operator=(my_unique_ptr&& _Y)
{
if (this == &_Y) return *this;
reset(_Y.release());
return *this;
}
_Dx& get_deletor()
{
return _myDeletor;
}
_Dx& get_deletor()const
{
return _myDeletor;
}
_Ty& operator*()const
{
return *_Ptr;
}
_Ty operator->()
{
return _Ptr;//&**this
}
pointer get()
{
return _Ptr;
}
operator bool()const
{
return _Ptr != NULL;
}
pointer release()
{
_Ty* old = _Ptr;
_Ptr = NULL;
return old;
}
void reset(pointer _p = NULL)//重置
{
pointer old = _Ptr;
_Ptr = _p;
if (old != NULL)
{
//_myDeletor(old);
get_deletor()(old);
}
}
void swap(my_unique_ptr _Y)
{
std::swap(_Ptr, _Y._Ptr);
std::swap(_myDeletor, _Y._myDeletor);
}
_Ty& operator[](size_t _Idx)const
{
return _Ptr[_Idx];
}
};
template<class _Ty,class ..._Type>
my_unique_ptr<_Ty>my_make_unique(_Type&& ..._arrys)
{
return my_unique_ptr<_Ty>(new_Ty(_arrys...));
}