天天看点

C++ 智能指针(unique_ptr / shared_ptr)代码实现

文章目录

  • ​​unique_ptr 智能指针的实现​​
  • ​​shared_ptr 智能指针的实现​​
  • ​​指针类型转换​​

unique_ptr 智能指针的实现

一个对象只能被单个unique_ptr 所拥有。

#include <iostream>

using namespace std;

/*增加模板类型,保证智能指针的类型是由传入的类型决定的*/
template <typename T>

class smart_ptr {
public:
    explicit smart_ptr(T *ptr = nullptr): ptr_(ptr){}
    
    /*移动构造函数,当前智能指针仅能被一个对象引用*/
    smart_ptr(smart_ptr&& other) {ptr_ = other.release();}
    
    /*如果我们想要消除移动构造和拷贝构造,只需要将其 构造标记为delete*/
    //smart_ptr(const smart_ptr&) = delete;
    //smart_ptr& operator=(const smart_ptr&) = delete;
    
    /*在构造参数时直接生成新的智能指针,从而不再需要在函数体中构造临时对象,当前支持移动构造进行函数对象的构造。*/
    smart_ptr& operator=(smart_ptr rhs) {
        rhs.swap(*this);
        return *this;
    }   
    
    T* release() {
        T* ptr = ptr_;
        ptr_ = nullptr;
        return ptr;
    }

    void swap(smart_ptr& rhs) {
        using std::swap;//标准模板库的交换函数
        swap(rhs.ptr_,ptr_);
    }

    ~smart_ptr(){delete ptr_;}
    T* get() const{ return ptr_;}
    
    /*指针的特性,可以通过*解引用访问 */
    T& operator*() const{return *ptr_;}
    /*指针的特性,可以通过-> 访问指针的地址内容*/
    T* operator->() const{return ptr_;}
    /*重载bool运算符,能够让smart_ptr像指针一样用在布尔表达式中*/
    operator bool() const{return ptr_;}

private:
    T* ptr_;
};

class Shape{
    public:
    virtual void create_shape() = 0;
    virtual ~Shape(){}
};

class Circle: public Shape{
    public:
    Circle(){cout << "Circle::Circle()" << endl;}
    void create_shape(){cout << "create shape: Circle" << endl;}
    ~Circle(){cout << "Circle::delete()" << endl;}
};

class Triangle: public Shape{
    public:
    Triangle(){cout << "Triangle::Tirangle()" << endl;}
    void create_shape(){cout << "create shape: Triangle" << endl;}
    ~Triangle(){cout << "Triangle::delete()" << endl;}
};

int main()
{
    smart_ptr<Shape> ptr1(new Circle);
    smart_ptr<Shape> ptr2(nullptr);
    smart_ptr<Shape> ptr3 ;
    
    //ptr3 = ptr1; //编译报错,赋值需要一个对象(而非引用),因而进入执行之前需要引发一个构造,但是此时没有可用的构造函数
     
    ptr3 = std::move(ptr2); // 编译正常,支持移动构造 
    
    return 0;
}      

shared_ptr 智能指针的实现

多个shared_ptr可以共享同一个对象,当他们全部失效的时候,这个对象才会被删除。

此时对shared_ptr的需求是共享 同一个对象时也需要共享同一个计数,当最后一个指向对象(和共享计数)的shared_ptr析构时,它需要删除对象和共享计数。

在以上unique_ptr的实现基础上增加引用计数相关的操作,实现如下:

#include <iostream>

using namespace std;

/*增加一个引用计数类,来记录当前对象被智能指针引用的次数*/
class shared_count{
public:
    shared_count():count_(1) {}
    
    void add_count(){
        ++count_;
    }
    
    long reduce_count(){
        return --count_;
    }

    long get_count() {
        return count_;
    }
private:
    long count_;
};

/*增加类模板,保证智能指针的类型是由传入的类型决定的*/
template <typename T>

class smart_ptr {
public:
    explicit smart_ptr(T *ptr = nullptr): ptr_(ptr){
        if(ptr) {
            shared_count_ = new shared_count();
        }
    }
    
    /*移动构造函数,当前智能指针仅能被一个对象引用,同时不进行引用计数的自加*/
    template <typename U>
    smart_ptr(smart_ptr<U>&& other) {
        ptr_ = other.release();
        if(ptr_) {
            shared_count_ = other.shared_count_;
            other.ptr_ = nullptr;
        }
    }

    /*拷贝构造函数,支持子类对象向父类对象的拷贝*/
    template <typename U>
    smart_ptr(const smart_ptr<U>& other) {
        ptr_ = other.ptr_;
        if(ptr_) {
            other.shared_count_ -> add_count();
            shared_count_ = other.shared_count_;
        }
    }

    /*同类型对象的拷贝构造函数*/
    smart_ptr(smart_ptr & other) {
        ptr_ = other.ptr_;
        if(ptr_) {
            other.shared_count_ -> add_count();
            shared_count_ = other.shared_count_;
        }
    }

    /*在构造参数时直接生成新的智能指针,从而不再需要在函数体中构造临时对象,当前支持移动构造进行函数对象的构造。*/
    smart_ptr& operator=(smart_ptr rhs) {
        rhs.swap(*this);
        return *this;
    }   
    
    T* release() {
        T* ptr = ptr_;
        ptr_ = nullptr;
        return ptr;
    }

    void swap(smart_ptr& rhs) {
        using std::swap;
        swap(rhs.ptr_,ptr_);
        swap(rhs.shared_count_,shared_count_);
    }
    
    long use_count() const {
        if(ptr_) {
            return shared_count_->get_count();
        } else {
            return 0;
        }
    }

    ~smart_ptr(){
    //  cout << "smart_ptr::delete count is " << shared_count_ -> get_count() << endl;
        if(ptr_ && !shared_count_ -> reduce_count()){
            delete ptr_;
            delete shared_count_;
        }
    }
    
    T* get() const{ return ptr_;}
    T& operator*() const{return *ptr_;}
    T* operator->() const{return ptr_;}
    operator bool() const{return ptr_;}

private:
    T* ptr_;
    shared_count* shared_count_;//统计对象引用计数的类
};


class Shape{
    public:
    virtual void create_shape() = 0;
    virtual ~Shape(){}
};

class Circle: public Shape{
    public:
    Circle(){cout << "Circle::Circle()" << endl;}
    void create_shape(){cout << "create shape: Circle" << endl;}
    ~Circle(){cout << "Circle::delete()" << endl;}
};

class Triangle: public Shape{
    public:
    Triangle(){cout << "Triangle::Tirangle()" << endl;}
    void create_shape(){cout << "create shape: Triangle" << endl;}
    ~Triangle(){cout << "Triangle::delete()" << endl;}
};

int main()
{
    smart_ptr<Shape> ptr1(new Circle);
    cout << "use count of ptr1 is: " << ptr1.use_count() << endl;
    
    smart_ptr<Shape> ptr2;
    cout << "use count of ptr2 was: " << ptr2.use_count() << endl;
    
    //ptr2 = std::move(ptr1); // 移动拷贝构造,不进行计数增加(可查看以上的实现)
    ptr2 = ptr1; //普通的拷贝构造,支持多个指针共享同一个对象,则对应智能指针的共享计数增加
    cout << "use count of ptr2 is now: " << ptr2.use_count() << endl;
    
    if(ptr1) {
        cout << "ptr1 is not empty " << endl;   
    }
    return 0;
}      

输出如下:

Circle::Circle()
use count of ptr1 is: 1
use count of ptr2 was: 0
use count of ptr2 is now: 2
Circle::delete()      

指针类型转换

​​C++已有的强制类型转换​​有如下几种:

  • static_cast 用于类层次结构中基类和派生类之间指针或引用的转换
  • reinterpret_cast 改变指针或引用的类型、将指针或引用转换为一个足够长度的整形、将整型转换为指针或引用类型
  • const_cast 用于强制去掉不能被修改的常数特性
  • dynamic_cast dynamic_cast是运行时处理的,运行时要进行类型检查。

智能指针需要实现类似的函数模板,想要达到以上对应的强制类型转换的功能,我们需要增加构造函数,且允许在对智能指针内部的指针对象赋值时,使用一个现有的智能指针的共享计数。如下所示:

template <typename U>
smart_ptr(const smart_ptr<U> &other, T* ptr) { //拷贝构造时,使用T* ptr进行类型转换
    _ptr = ptr;
    if(_ptr) {
        other.shared_count_ -> add_count();
        shared_count_ = other.shared_count_;
    }
}      

根据以上代码,实现​

​dynamic_pointer_cast​

template <typename T, typename U>
smart_ptr <T> dynamic_pointer_cast(
    const smart_ptr<U> &other) {
    T *ptr = dynamic_cast<T*> (other.get());
    return smart_ptr<T> (other,ptr);
}      

使用方式如下:

template <typename T, typename U>
smart_ptr <T> static_pointer_cast(
    const smart_ptr<U> &other) {
    T *ptr = static_cast<T*> (other.get());
    return smart_ptr<T> (other,ptr);
}

template <typename T, typename U>
smart_ptr <T> reinterpret_pointer_cast(
    const smart_ptr<U> &other) {
    T *ptr = reinterpret_cast<T*> (other.get());
    return smart_ptr<T> (other,ptr);
}

template <typename T, typename U>
smart_ptr <T> const_pointer_cast(
    const smart_ptr<U> &other) {
    T *ptr = const_cast<T*> (other.get());
    return smart_ptr<T> (other,ptr);
}      

继续阅读