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

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

文章目录

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

unique_ptr 智能指针的实现

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

#include 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 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);
}

使用方式如下:

smart_ptr ptr3 = dynamic_pointer_cast ptr2;

同理实现其他三个 强制类型转换的逻辑实现如下:

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);
}

更多相关:

  • C++11标准中可以为模板定义别名,比如 template using ptr=std::shared_ptr; //这里模板定义ptr为智能指针std::shared_ptr定义的别名 所以实际应用中可以借此来简化代码,比如 #include #include

  • 先说结论,智能指针都是非线程安全的。 多线程调度智能指针 这里案例使用的是shared_ptr,其他的unique_ptr或者weak_ptr的结果都是类似的,如下多线程调度代码: #include #include #include #include #i...

  • 文章目录weak_ptr描述声明作用原理实现函数成员使用总结 weak_ptr描述 声明 头文件: 模版类:template class weak_ptr 声明方式:std::weak_ptr statement 作用 根据boost库的官方描述,weak_ptr是...

  • 文章目录shared_ptr描述声明作用原理实现函数使用关于shared_ptr循环引用问题 shared_ptr描述 声明 shared_ptr属于C++11特性中新加的一种智能指针,它的实现方式是模版类,头文件 template class shared_ptr 所以使用shared...

  • 如何使用Python快速高效地统计出大文件的总行数, 下面是一些实现方法和性能的比较。1.readline读所有行使用readlines方法读取所有行:def readline_count(file_name):return len(open(file_name).readlines())2.依次读取每行依次读取文件每行内容进行计数:...

  • 关于逆序数的问题描述如下: 已知数组nums,求新数组count,count[i]代表了在nums[i]右侧且比 nums[i]小的元素个数。 例如: nums = [5, 2, 6, 1], count = [2, 1, 1, 0]; nums = [6, 6, 6, 1, 1, 1], count = [3, 3, 3, 0,...

  • 题目 设计一个算法,计算出n阶乘中尾部零的个数 样例 11! = 39916800,因此应该返回 2   题解 一开始就用最简单对1-n找出5的个数,然后超时了。虽然都直到是要找5,因为2肯定比5多,所以5的个数就是0的个数,只是计算方法得简单明了。既然1-n里5的个数就是0,我们就看看规律。5 10 15 。。。n 那n/...

  • EditText 限定中文8个英文16个的解决方法。 在EditText上控件提供的属性中有限定最大最小长度的方法。可是,对于输入时,限定中文8个英文16个时,怎么办?相当于一个中文的长度是两个英文的长度。 原理就不说了。自己看一下android的源代码。 以上直接上代码。 private final int maxLen =...

  • /**172. Factorial Trailing Zeroes *2016-6-4 by Mingyang* 首先别忘了什么是factorial,就是阶乘。那么很容易想到需要统计* (2,5)对的个数,因为2×5=10。但是这个条件放松一下就会发现其实只要数5的个数就好了,* 因为2实在是比5要多的多。那么这道题目就转...