unique_ptr和share_ptr的简单实现
unique_ptr的简单实现
来自
实现智能指针1:unique_ptr
下面列出需要注意的知识点:
1.异常
2.unique_ptr本身功能
3.三五法则和阻止拷贝
4.隐式的类类型转换
5.移动构造、移动赋值及自赋值问题
6.编写模板类。
//reference: https://www.jianshu.com/p/77c2988be336
//第一次错误:在模板类外定义成员函数时,需要声明template<typename T>
// 同时应该是 返回值 类<T>:: 成员函数(参数){}这种格式
template<typename T>
class MyUniquePtr{
public:
//显式构造
explicit MyUniquePtr(T* ptr=nullptr):mPtr(ptr){
}
~MyUniquePtr(){
if(mPtr!=nullptr)
delete mPtr;
}
//移动构造,注意右值引用p会被修改,所以不能用const
MyUniquePtr(MyUniquePtr&& p) noexcept;
//移动赋值,同理不能用const
MyUniquePtr& operator=(MyUniquePtr&& p) noexcept;
//禁止赋值构造和赋值运算符
MyUniquePtr(const MyUniquePtr& p)=delete;
MyUniquePtr& operator=(const MyUniquePtr& p)=delete;
//重载指针的功能
T* operator->()const noexcept{
return mPtr;
}
T& operator*()const noexcept{
return *mPtr;
}
//使MyUniquePtr能够根据上下文转换为bool类型
explicit operator bool() const noexcept{
return mPtr;
}
//释放原来的空间,然后指向新的地址空间
void reset(T* q=nullptr) noexcept{
if(mPtr!=q){
if(mPtr!=nullptr)
delete mPtr;
mPtr=q;
}
}
//指针置nullptr,原先地址作为返回值返回
T* release() noexcept{
T* res=mPtr;
mPtr=nullptr;
return res;
}
//返回内部指针
T* get()const noexcept{
return mPtr;
}
/*
了解一下std::swap的一些特性
1.大概全貌如下:
template<typename T>
void swap(T &a,T &b) noexcept
{
T temp = std::move(a);
a = std::move(b);
b = std::move(temp);
}
2.要求T必须满足MoveAssignable和MoveConstructible
通俗讲就是有移动构造函数和移动赋值函数
*/
void swap(MyUniquePtr& p) noexcept{
using std::swap;
swap(mPtr,p.mPtr);
}
private:
T* mPtr;
};
//移动构造函数(Move Constructors)和移动赋值运算符( Move Assignment Operator)从给定对象窃取资源而不是拷贝资源
template<typename T>
MyUniquePtr<T>::MyUniquePtr(MyUniquePtr&& p) noexcept: mPtr(p.mPtr){
p.mPtr=nullptr;
}
//这里用swap来避免 在实现赋值运算符是需要检查自我赋值的情况
//https://www.geeksforgeeks.org/copy-swap-idiom-c/
template<typename T>
MyUniquePtr<T>& MyUniquePtr<T>::operator=(MyUniquePtr&& p) noexcept{
swap(p);
return *this;
}
shared_ptr的简单实现
一般来说,智能指针的实现需要以下步骤:
1.一个模板指针T* ptr,指向实际的对象。
2.一个引用次数(必须new出来的,不然会多个shared_ptr里面会有不同的引用次数而导致多次delete)。
3.重载operator*和operator->,使得能像指针一样使用shared_ptr。
4.重载copy constructor,使其引用次数加一。
5.重载operator=,如果原来的shared_ptr已经有对象,则让其引用次数减一并判断引用是否为零(是否调用delete)。
然后将新的对象引用次数加一。
6.重载析构函数,使引用次数减一并判断引用是否为零(是否调用delete)。
#ifndef __SHARED_PTR_
#define __SHARED_PTR_
template <typename T>
class shared_ptr {
public:
shared_ptr(T* p) : count(new int(1)), _ptr(p) {}
shared_ptr(shared_ptr<T>& other) : count(&(++*other.count)), _ptr(other._ptr) {}
T* operator->() { return _ptr; }
T& operator*() { return *_ptr; }
shared_ptr<T>& operator=(shared_ptr<T>& other)
{
//检查自我赋值
if(this==&other) return *this;
++*other.count;
if (this->_ptr && 0 == --*this->count)
{
delete count;
delete _ptr;
}
this->_ptr = other._ptr;
this->count = other.count;
return *this;
}
~shared_ptr()
{
if (--*count == 0)
{
delete count;
delete _ptr;
}
}
int getRef() { return *count; }
private:
int* count;
T* _ptr;
};
#endif