2021-07-30

一个简易的unique_ptr实现

  unique_ptr关键在于几个构造函数与移动函数。unique_ptr拥有两部分数据,一部分是裸指针,另一部分是删除器,本份代码实现不包括删除器,所以它的大小与裸指针相同。

​  unique_ptr主要的创建方式有两种,一是通过裸指针创建,二是通过一个右值unique_ptr对象进行移动构造。裸指针创建不需要解释,但是无论是标准unique_ptr版本还是这份实现,都是允许使用指针作为一个左值传入unique_ptr的构造函数中。为了实现仅能通过右值对象移动构造,需要将拷贝构造与拷贝赋值函数都声明为delete:

unique_ptr(const unique_ptr&)=delete;
unique_ptr& operator=(const unique_ptr&)=delete;

​  实现移动构造(移动赋值同理)时,需要使用一个函数模板,来使得不同类型的指针之间可以实现转换(如子类指针转化为基类指针)。标准库的实现利用了enable_if模板,它通过辅助的模板判断两个指针之间是否可以安全的转化,并利用判断结果产生合适的代码。这里就粗糙一点,直接用模板上了:

template<typename Ep>
unique_ptr(unique_ptr<Ep>&& rhs):raw_p(rhs.release()){}

​  这份实现的接口和标准unique_ptr相同(除了没有删除器),故release()函数就是当前unique_ptr释放对于资源的控制权,并返回相应的裸指针;reset(pointer p=nullptr)接收一个可选参数,它会重新设置当前unique_ptr所管理的资源。

​  智能指针能够表现的像一般指针,C++强大的操作符重载能力不可或缺。首先便是两个解引用符号:

reference operator*() const
{
        return *raw_p;
}
pointer operator->() const
{
        return &(this->operator*());
}

​  这两个解引用符号第一个比较好理解,第二种形式有些奇怪,能记住就行。基本上这类成对出现的操作符,都是用其中一个实现另外一个。

​  bool运算符以及!运算符可以用于指针的条件判断,像if(!up)之类都是程序员常用的判断指针是否为空的方式。bool类型转换运算符很简单,因为这两个操作一般也是一起出现的,所以也是通过bool运算符来实现!运算符的重载:

operator bool() const
{
        return raw_p!=nullptr;
}
bool operator!() const
{
        return !(this->operator bool());
}

​  全部代码如下:

#include<string>
#include<vector>
#include<iostream>

template<typename Up>
class unique_ptr
{
        using pointer   = Up*;
        using reference = Up&;
public:
        unique_ptr():raw_p(nullptr){}
		
        unique_ptr(pointer rhs):raw_p(rhs){}

        template<typename Ep>
        unique_ptr(unique_ptr<Ep>&& rhs):raw_p(rhs.release()){}

        template<typename Ep>
        unique_ptr& operator=(unique_ptr<Ep>&& rhs)
        {
                reset(rhs.release());
                return *this;
        }

        unique_ptr(const unique_ptr&)=delete;

        unique_ptr& operator=(const unique_ptr&)=delete;

        ~unique_ptr() noexcept
        {
                if(raw_p)
                        delete raw_p;
        }

        reference operator*() const
        {
                return *raw_p;
        }

        pointer operator->() const
        {
                return &(this->operator*());
        }

        operator bool() const
        {
                return raw_p;
        }

        bool operator!() const
        {
                return !(this->operator bool());
        }

    	bool operator==(const unique_ptr& rhs) const
        {
            	return raw_p==rhs.raw_p;
        }
    
    	bool operator!=(const unique_ptr& rhs) const
        {
    			return !(this->operator==(rhs));        
        }
    
        pointer release()
        {
                pointer temp=raw_p;
                raw_p=nullptr;
                return temp;
        }

        void reset(pointer p=nullptr)
        {
                pointer temp=raw_p;
                raw_p=p;
                if(temp!=nullptr)
                        delete temp;
        }

        void swap(const unique_ptr& rhs) noexcept
        {
                std::swap(raw_p,rhs.raw_p);
        }
private:
        pointer raw_p;
};

template<typename T,typename...Args>
unique_ptr<T> make_unique(Args&&...args)
{
        return unique_ptr<T>(new T(std::forward<Args>(args)...));
}

int main()
{
        unique_ptr<std::string> up1(new std::string("up1"));

        std::string *sp=new std::string("up2");
        unique_ptr<std::string> up2(sp);

        auto up3(make_unique<std::string>("up3"));

        std::cout<<*up1<<"  "<<*up2<<"  "<<*up3<<"  \n";
}
上一篇:数据挖掘(一)——数据探索(EDA)


下一篇:openLayer点击要素获取对应的属性信息