C++ unique_ptr介绍及仿写
Posted Jqivin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ unique_ptr介绍及仿写相关的知识,希望对你有一定的参考价值。
一、unique_ptr的使用
(1)构造函数不能进行隐式转换。
(2)unique_ptr可以指向动态数组。因为unique_ptr有unique_ptr<T[]>重载版本,销毁动态对象时调用delete[]。
(3)unique_ptr无拷贝语义,但提供了移动语义,所以可作为函数返回值。与容器在一块使用时要注意。
(4)谨慎使用智能指针的get与release方法
当使用get方法返回裸指针时,智能指针并没有释放指向对象的所有权,所以我们必须小心使用裸指针以避免程序崩溃。但通过unique_ptr.release()方法返回的裸指针,需要我们自己delete删除对象,因为调用release方法后,该unique_ptr不再拥有对象的所有权。
class Object
{
private:
int value;
public:
Object(int val = 0) :value(val) { cout << "construct Object" << endl; }
~Object() { cout << "destruct Object" << endl; }
int Value() { return value; }
const int Value() const { return value; }
};
int main()
{
unique_ptr<Object> pO(new Object(10));
unique_ptr<Object> pO2(new Object(20));
unique_ptr<int> pi(new int(1));
cout << pO->Value() << endl;
cout << *pi << endl;
//pO = pO2; //编译不通过,不能拷贝构造或者赋值
pO = std::move(pO2); //移动之后pO2就析构掉了
//cout << pO2->Value() << endl; //错误:如果不注释掉就执行失败,因为pO2已经没有对象资源的所有权了
cout << pO->Value() << endl;
int* p = pi.release();
// cout << *pi << endl; //错误:release之后也会释放资源的所有权
cout << "*p=" << *p << endl; delete p;
cout << endl;
unique_ptr<int[]> ps1(new int[10]{ 1,2,3,4,5,6,7,8,9,10 });
//cout << *ps1 << endl; 特化版本不重载* ->
for (int i = 0; i < 10; i++)
{
cout << ps1[i] << " ";
}
cout << endl;
Object* Obj = new Object[]{ 10,20,30 };
delete[]Obj;
unique_ptr<Object[] > pobj(new Object[]{ 10,20,30 });
cout << pobj[0].Value() << endl;;
return 0;
}
结果
二、unique_ptr类的成员方法
1.非特化版本
2.特化版本
缺少运算符*,->的重载,多了[]的重载;
get()函数
:只是得到unique_ptr指向的资源
release()
:函数是释放unique_ptr指向的资源,返回值是指向的资源
swap()
:交换两个unique_ptr指向的资源,参数是unique_ptr类型
reset()
:重置unique_ptr指向的资源,先释放原来的资源,然后将指针指向新的资源。参数是指针类型,而不是unique_ptr类型。
int main()
{
unique_ptr<int> up(new int(10));
int* p = up.get(); //get()只是得到unique_ptr指向的资源
cout << "*p=" << *p << endl; //10
cout << "*up=" << *up << endl; //10
unique_ptr<int> up2(new int(20));
up2.swap(up); //交换资源
cout << *up <<" " << *up2 << endl; //20 10
up2.reset(new int(30));
cout << *up2 << endl; //30
int* p2 = up.release(); //release释放unique_ptr对资源的所有权
cout << "*p2=" << *p2 << endl; //20
cout << "*up=" << *up << endl; //出错,已经不拥有资源了
return 0;
}
三、仿写
#include<iostream>
using namespace std;
#if 1
namespace jqw
{
//默认的删除器
template <class _Ty>
struct default_delete
{public:
void operator()(_Ty* ptr)const
{
delete ptr;
}
};
//数组的删除器
template <class _Ty>
struct default_delete<_Ty[]>
{
void operator()(_Ty* ptr)const
{
delete []ptr;
}
};
template <class _Ty, typename _Dp = default_delete<_Ty>>
class unique_ptr
{
private:
_Ty* _Ptr;
public:
typedef _Ty* pointer;
typedef _Ty element_type;
typedef _Dp delete_type;
delete_type get_deleter() { return delete_type(); } //删除器获取函数
//构造函数 不可以隐式转换
explicit unique_ptr(_Ty* ptr = nullptr):_Ptr(ptr){}
//析构函数
~unique_ptr()
{
if (_Ptr)
{
//delete _Ptr;
get_deleter()(_Ptr);
}
}
//拷贝构造和赋值函数delete掉
unique_ptr(unique_ptr<_Ty>& p) = delete;
unique_ptr<_Ty>& operator=(const unique_ptr<_Ty>& p) = delete;
//移动构造函数和移动赋值
unique_ptr(unique_ptr<_Ty>&& p)
{
if (_Ptr != p._Ptr)
{
//delete _Ptr; //XXXXXXXXXXX
get_deleter()(_Ptr);
_Ptr = p._Ptr;
p._Ptr = nullptr;
}
}
unique_ptr<_Ty>& operator=(unique_ptr<_Ty>&& p)
{
if (this != &p)
{
//delete _Ptr;
get_deleter()(_Ptr);
_Ptr = p._Ptr;
p._Ptr = nullptr;
}
return *this;
}
//获取资源
pointer get() const
{
return _Ptr;
}
//判断智能指针是否拥有资源 ?????、返回类型
explicit operator bool() const
{
return _Ptr != nullptr;
}
//重载运算符* ->
_Ty* operator->() const
{
return get();
}
const _Ty& operator*() const
{
return *_Ptr;
}
//释放函数
pointer release()
{
_Ty* tmp = this->_Ptr;
this->_Ptr = nullptr;
return tmp;
}
//重置资源
void reset(_Ty* p = nullptr)
{
//delete _Ptr; //XXXXX
get_deleter()(_Ptr);
_Ptr = p;
}
//交换
void swap(unique_ptr& _u)
{
std::swap(_Ptr, _u._Ptr);
}
};
//
template <class _Ty, typename _Dp>
class unique_ptr<_Ty[],_Dp> //特化版本,用户可以自己写 _Dp 删除器
{
private:
_Ty* _Ptr;
public:
typedef _Ty* pointer;
typedef _Ty element_type;
typedef _Dp delete_type;
delete_type get_deleter() { return delete_type(); } //删除器获取函数
//构造函数
explicit unique_ptr(_Ty* ptr = nullptr) :_Ptr(ptr) {}
//析构函数
~unique_ptr()
{
if (_Ptr)
{
//delete _Ptr;
get_deleter()(_Ptr);
}
}
//拷贝构造和赋值函数delete掉
unique_ptr(unique_ptr<_Ty>& p) = delete;
unique_ptr<_Ty>& operator=(const unique_ptr<_Ty>& p) = delete;
//移动构造函数和移动赋值
unique_ptr(unique_ptr<_Ty>&& p)
{
if (_Ptr != p._Ptr)
{
//delete _Ptr; //XXXXXXXXXXX
get_deleter()(_Ptr);
_Ptr = p._Ptr;
p._Ptr = nullptr;
}
}
unique_ptr<_Ty>& operator=(unique_ptr<_Ty>&& p)
{
if (this != &p)
{
delete _Ptr;
_Ptr = p._Ptr;
p._Ptr = nullptr;
}
return *this;
}
//获取资源
pointer get() const
{
return _Ptr;
}
//判断智能指针是否拥有资源 ?????、返回类型
explicit operator bool() const
{
return _Ptr != nullptr;
}
//重载运算符* ->
_Ty* operator->() const
{
return get();
}
const _Ty& operator*() const
{
return *_Ptr;
}
//释放函数
pointer release()
{
_Ty* tmp = this->_Ptr;
this->_Ptr = nullptr;
return tmp;
}
//重置资源
void reset(_Ty* p = nullptr)
{
//delete _Ptr; //XXXXX
get_deleter()(_Ptr);
_Ptr = p;
}
//交换
void swap(unique_ptr& _u)
{
std::swap(_Ptr, _u._Ptr);
}
_Ty& operator[](int index)
{
return _Ptr[index];
}
};
}
class Object
{
private:
int value;
public:
Object(int val = 0) :value(val) { cout << "construct Object" << endl; }
~Object() { cout << "destruct Object" << endl; }
int Value() { return value; }
const int Value() const { return value; }
};
int main()
{
jqw::unique_ptr<Object> pO(new Object(10));
jqw::unique_ptr<Object> pO2(new Object(20));
jqw::unique_ptr<int> pi(new int(1));
cout << pO->Value() << endl;
cout << *pi << endl;
//pO = pO2; //编译不通过,不能拷贝构造或者赋值
pO = std::move(pO2); //移动之后pO2就析构掉了
//cout << pO2->Value() << endl; //错误:如果不注释掉就执行失败,因为pO2已经没有对象资源的所有权了
cout << pO->Value() << endl;
int* p = pi.release();
// cout << *pi << endl; //错误:release之后也会释放资源的所有权
cout << "*p=" << *p << endl; delete p;
cout << endl;
jqw::unique_ptr<int[]> ps1(new int[10]{ 1,2,3,4,5,6,7,8,9,10 });
cout << *ps1 << endl;
for (int i = 0; i < 10; i++)
{
cout << ps1[i] << " ";
}
cout << endl;
Object* Obj = new Object[]{ 10,20,30 };
delete []Obj;
jqw::unique_ptr<Object[] > pobj(new Object[]{ 10,20,30 });
cout << pobj[0].Value() << endl;;
return 0;
}
#endif
结果:和系统提供的一致,(仿写特化版本没有删除* ->的重载)
以上是关于C++ unique_ptr介绍及仿写的主要内容,如果未能解决你的问题,请参考以下文章
如何将 unique_ptr 从一组移动到另一组? (C++)
使用 std::unique_ptr 的 C++ Pimpl Idiom 不完整类型