一.unique_ptr的概念
unique_ptr 智能指针对象,可以独占的管理其所有权。
二.unique_ptr 特点∶
1 .基于排他所有权模式:两个指针不能指向同一个资源。
2 .由于独占对象的拥有权,所以不提供拷贝构造函数和左值赋值函数重载。
3 .提供移动构造和移动赋值函数。
4 .为了实现单个对象和一组对象的管理,添加了删除器类型。
5 .在容器保存指针是安全。
6 .unique_ptr具有->和*运算符重载符,因此它可以像普通指针一
样使用。
我们基于唯一性智能指针的特性去实现这些方法。
0.模板类的成员变量展示
template<class _Ty, class _Dx = Default_deleter<_Ty>>
class My_unique_ptr
{
public:
/*explicit 指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式,即它不能用于隐式转换和复制初始化。
*/
explicit My_unique_ptr(_Ty* ptr = nullptr) :m_ptr(ptr) { std::cout << "creat My_unique_ptr"; }
~My_unique_ptr() { m_deleter(m_ptr); }
public:
using pointer = _Ty*;
using element_type = _Ty;
using deleter_type = _Dx;
pointer m_ptr;
_Dx m_deleter;
};
1.构造函数,析构函数
/*explicit*/My_unique_ptr(_Ty* ptr = nullptr) :m_ptr(ptr)
{ std::cout << "creat My_unique_ptr";
}
~My_unique_ptr()
{
m_deleter(m_ptr);
}
class Int
{
public:
Int() :x_(0) { std::cout << "creat Int"; x_ += 1; }
Int(int x) :x_(x) { std::cout << "creat Int"; }
Int(int x, int y):x_(x) { std::cout << "creat Int"; }
void Print()
{
std::cout << "Int::" << x_;
}
public:
int x_;
};
explicit:指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式,即它不能用于隐式转换和复制初始化。如下:
My_unique_ptr<Int>tmp1 = new Int(12, 3); //error :加上关键字不允许 隐式转换。
2.为了满足智能指针的唯一性,不允许拷贝构造和赋值运算符的重载
代码:
My_unique_ptr(const My_unique_ptr&) = delete;
My_unique_ptr& operator=(const My_unique_ptr&) = delete;
但提供了移动构造和移动赋值:
My_unique_ptr(My_unique_ptr&& other) :m_ptr(other.m_ptr) { other.m_ptr = nullptr; }
My_unique_ptr& operator=(My_unique_ptr&& other)
{
if (this != &other)
{
delete m_ptr;
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
}
return *this;
} //xxxx
3.几个方法:
pointer release()
{
pointer ptr = m_ptr; // 释放所有权不是将内存回收
m_ptr = nullptr;
return ptr;
}
pointer get()const
{
return m_ptr;
}
void swap(const pointer ptr)
{
std::swap(m_ptr, ptr);
}
pointer operator->()const
{
return m_ptr;
}
element_type& operator *()const
{
return *m_ptr;
}
4.删除器的实现:
唯一性智能指针功能上支持一个或多个对象的管理。那么怎么管理一组对象?
这里我们用到的方法是:先在类中构建一个删除器对象,在智能指针类析构函数中利用仿函数和模板类和模板类的部分特化实现分别可以删除一个对象和一组对象。
template<class _Ty>
struct Default_deleter
{
void operator() (_Ty* ptr)
{
delete ptr;
ptr = nullptr;
std::cout << "destroyed";
}
};
template<class _Ty>
struct Default_deleter<_Ty[]>
{
void operator ()(_Ty* ptr)
{
delete[]ptr;
ptr = nullptr;
std::cout << "destroyed ";
}
};
智能化指针对象构建时如何区别一个和一组对象。答案是也用到了模板类的特化。
完整代码如下:
#if 1
template<class _Ty>
struct Default_deleter
{
void operator() (_Ty* ptr)
{
delete ptr;
ptr = nullptr;
std::cout << "destroyed";
}
};
template<class _Ty>
struct Default_deleter<_Ty[]>
{
void operator ()(_Ty* ptr)
{
delete[]ptr;
ptr = nullptr;
std::cout << "destroyed ";
}
};
template<>
struct Default_deleter<FILE>
{
void operator()(FILE* f)
{
fclose(f);
std::cout << "fclose doc" << std::endl;
}
};
template<class _Ty, class _Dx = Default_deleter<_Ty>>
class My_unique_ptr
{
public:
/*explicit 指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式,即它不能用于隐式转换和复制初始化。
*/
explicit My_unique_ptr(_Ty* ptr = nullptr) :m_ptr(ptr) { std::cout << "creat My_unique_ptr"; }
~My_unique_ptr() { m_deleter(m_ptr); }
My_unique_ptr(const My_unique_ptr&) = delete;
My_unique_ptr& operator=(const My_unique_ptr&) = delete;
public:
using pointer = _Ty*;
using element_type = _Ty;
using deleter_type = _Dx;
pointer m_ptr;
_Dx m_deleter;
public:
My_unique_ptr(My_unique_ptr&& other) :m_ptr(other.m_ptr) { other.m_ptr = nullptr; }
My_unique_ptr& operator=(My_unique_ptr&& other)
{
if (this != &other)
{
delete m_ptr;
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
}
return *this;
}
pointer release()
{
pointer ptr = m_ptr; // 释放所有权不是将内存回收
m_ptr = nullptr;
return ptr;
}
pointer get()const
{
return m_ptr;
}
void swap(const pointer ptr)
{
std::swap(m_ptr, ptr);
}
pointer operator->()const
{
return m_ptr;
}
element_type& operator *()const
{
return *m_ptr;
}
};
template<class _Ty,class _Dx>
class My_unique_ptr<_Ty[],_Dx>
{
public:
/*explicit 指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式,即它不能用于隐式转换和复制初始化。
*/
explicit My_unique_ptr(_Ty* ptr = nullptr) :m_ptr(ptr) { std::cout << "creat My_unique_ptr"; }
~My_unique_ptr() { m_deleter(m_ptr); }
My_unique_ptr(const My_unique_ptr&) = delete;
My_unique_ptr& operator=(const My_unique_ptr&) = delete;
public:
using pointer = _Ty*;
using element_type = _Ty;
using deleter_type = _Dx;
pointer m_ptr;
_Dx m_deleter;
public:
My_unique_ptr(My_unique_ptr&& other) :m_ptr(other.m_ptr) { other.m_ptr = nullptr; }
My_unique_ptr& operator=(My_unique_ptr&& other)
{
if (this != &other)
{
delete m_ptr;
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
}
return *this;
}
pointer release()
{
pointer ptr = m_ptr; // 释放所有权不是将内存回收
m_ptr = nullptr;
return ptr;
}
pointer get()const
{
return m_ptr;
}
void swap(const pointer ptr)
{
std::swap(m_ptr, ptr);
}
_Ty& operator[](const size_t i)const
{
return get()[i];
}
};
template<class _Ty, class ... Types,enable_if_t<!is_array_v<_Ty>,int > =0>
My_unique_ptr<_Ty> My_make_unique(Types &&... Args) //函数形式
{
return My_unique_ptr<_Ty>(new _Ty(std::forward<Types>(Args)...));
}
//make_unique如何实现管理一组对象?
template<class _Ty, enable_if_t<is_array_v<_Ty>, int > = 0>//is_array_v是否是数组类型
My_unique_ptr<_Ty> My_make_unique(const std::size_t size) //函数形式
{
using _Elem = remove_extent_t<_Ty>;//去除_Ty数组特性,保留类型
return My_unique_ptr<_Ty>(new _Elem[size]{});//new _Elem[size]{} 和new _Elem[size]区别
}
class Int
{
public:
Int() :x_(0) { std::cout << "creat Int"; x_ += 1; }
Int(int x) :x_(x) { std::cout << "creat Int"; }
Int(int x, int y):x_(x) { std::cout << "creat Int"; }
void Print()
{
std::cout << "Int::" << x_;
}
public:
int x_;
};
int main()
{
//FILE* fptr;
My_unique_ptr<Int[]>test(new Int[10]);
//test.
//My_unique_ptr<Int>tmp1 = new Int(12, 3);
//My_unique_ptr<FILE>fptr(fopen("lmy.txt", "w"));
//fprintf(fptr.get(), "%d ,%d, %d", 10, 20, 30);
/*My_unique_ptr<Int>tmp = My_make_unique<Int>(3);
My_unique_ptr<Int>tmp1 = My_make_unique<Int>(12,3);*/
//My_unique_ptr<Int[]>tmp2 = My_make_unique<Int[]>(12);
//auto ptr = new Int[3];
///*My_unique_ptr<char[]>pa(new char[10]);*/
return 0;
}
#endif
注意:类模板函数模板的特化版本需要普通模板类或函数模板在其前面已经实现才可以。