C++中智能指针unique_ptr的实现详解

 更新时间:2024年01月17日 08:10:34   作者:李慕然  
智能指针本质上并不神秘,其实就是 RAII 资源管理功能的自然展现而已,这篇文章主要为大家详细介绍了如何实现 C++中智能指针的 unique_ptr,需要的可以了解下

前言

智能指针本质上并不神秘,其实就是 RAII 资源管理功能的自然展现而已。本文将介绍如何实现 C++中智能指针的 unique_ptr。

实现过程

首先,unique_ptr 能够包装任意类型,所以,要让这个类能够包装任意类型的指针,我们需要把它变成一个类模板。

template <typename T>
class unique_ptr {
public:
  explicit unique_ptr(T* ptr = nullptr)
    : ptr_(ptr) {}
  ~unique_ptr()
  {
    delete ptr_;
  }
  T* get() const { return ptr_; }
private:
  T* ptr_;
};

目前这个 unique_ptr 的行为还是和指针有点差异的:

  • 它不能用 * 运算符解引用
  • 它不能用 -> 运算符指向对象成员
  • 它不能像指针一样用在布尔表达式里

不过,这些问题也相当容易解决,加几个成员函数就可以:

template <typename T>
class unique_ptr {
public:
  …
  T& operator*() const { return *ptr_; }
  T* operator->() const { return ptr_; }
  operator bool() const { return ptr_; }
}

拷贝构造和赋值

最简单的情况显然是禁止拷贝。我们可以使用下面的代码:

template <typename T>
class unique_ptr {
  …
  unique_ptr(const unique_ptr&) = delete;
  unique_ptr& operator=(const unique_ptr&) = delete;
  …
};

禁用这两个函数非常简单,但是,有时我们需要转移所有权,那么这个方案就不可行了。

这里,我们采用移动语义:

template <typename T>
class unique_ptr {
  …
  unique_ptr(unique_ptr&& other)
  {
    ptr_ = other.release();
  }
  unique_ptr& operator=(unique_ptr rhs)
  {
    rhs.swap(*this);
    return *this;
  }
  …
};
  • 把拷贝构造函数中的参数类型 unique_ptr& 改成了 unique_ptr&&;现在它成了移动构造函数。
  • 把赋值函数中的参数类型 unique_ptr& 改成了 unique_ptr,在构造参数时直接生成新的智能指针,从而不再需要在函数体中构造临时对象。现在赋值函数的行为是移动还是拷贝,完全依赖于构造参数时走的是移动构造还是拷贝构造。 根据 C++ 的规则,如果我提供了移动构造函数而没有手动提供拷贝构造函数,那后者自动被禁用。

子类指针向基类指针的转换

一个 circle* 类是可以隐式转换成 shape* 类的,但上面的 unique_ptr<circle> 却无法自动转换成 unique_ptr<shape>

不过,只需要额外加一点模板代码,就能实现这一行为。在我们目前给出的实现里,只需要增加一个构造函数即可。

template <typename U>
unique_ptr(unique_ptr<U>&& other)
{
  ptr_ = other.release();
}

这样,我们自然而然利用了指针的转换特性:现在 unique_ptr<circle> 可以移动给 unique_ptr<shape>,但不能移动给 unique_ptr<triangle>。不正确的转换会在代码编译时直接报错。

验证

unique_ptr<shape> ptr1{create_shape(shape_type::circle)};
unique_ptr<shape> ptr2{ptr1};             // 编译出错
unique_ptr<shape> ptr3;
ptr3 = ptr1;                             // 编译出错
ptr3 = std::move(ptr1);                  // OK,可以
unique_ptr<shape> ptr4{std::move(ptr3)};  // OK,可以

完整代码

#include <utility>

template <typename T>
class unique_ptr {
public:
  explicit unique_ptr(T* ptr = nullptr)
    : ptr_(ptr) {}
  ~unique_ptr()
  {
    delete ptr_;
  }
  unique_ptr(unique_ptr&& other)
  {
    ptr_ = other.release();
  }
  // 子类指针向基类指针的转换
  template <typename U>
  unique_ptr(unique_ptr<U>&& other)
  {
    ptr_ = other.release();
  }
  unique_ptr& operator=(unique_ptr rhs)
  {
    rhs.swap(*this);
    return *this;
  }
  T* release()
  {
    T* ptr = ptr_;
    ptr_ = nullptr;
    return ptr;
  }
  void swap(unique_ptr& rhs)
  {
    using std::swap;
    swap(ptr_, rhs.ptr_);
  }
  T* get() const { return ptr_; }
  T& operator*() const { return *ptr_; }
  T* operator->() const { return ptr_; }
  operator bool() const { return ptr_; }
private:
  T* ptr_;
};

总结

自行实现一个 unique_ptr 相对比较简单,因为不涉及引用计数,只需要一个对象只能被单个 unique_ptr 所拥有。

以上就是C++中智能指针unique_ptr的实现详解的详细内容,更多关于C++智能指针unique_ptr的资料请关注脚本之家其它相关文章!

相关文章

  • c++项目中后缀名vcxproj和sln的区别及说明

    c++项目中后缀名vcxproj和sln的区别及说明

    这篇文章主要介绍了c++项目中后缀名vcxproj和sln的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • C++中的函数返回值与拷贝用法

    C++中的函数返回值与拷贝用法

    这篇文章主要介绍了C++中的函数返回值与拷贝用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • OpenCV 通过Mat遍历图像的方法汇总

    OpenCV 通过Mat遍历图像的方法汇总

    对图像中的所有点或特殊点进行运算,所以遍历图像就显得很重要,如何高效的遍历图像是一个很值得探讨的问题,本文给大家带来了多种方法操作OpenCV 通过Mat遍历图像,感兴趣的朋友一起看看吧
    2022-02-02
  • C++ 整型与字符串的互转方式

    C++ 整型与字符串的互转方式

    今天小编就为大家分享一篇C++ 整型与字符串的互转方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-12-12
  • C语言小程序 如何判断两个日期之差

    C语言小程序 如何判断两个日期之差

    输入两个日期,计算之间相差多少天。 用了两种方法实现,第二种利用结构体,代码比较清晰,其余的都一样
    2013-07-07
  • CRC校验原理及其C语言实现详解

    CRC校验原理及其C语言实现详解

    循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术。本文主要介绍了CRC校验原理及其C语言实现,感兴趣的可以了解一下
    2023-03-03
  • C 语言注释和变量使用基础详解

    C 语言注释和变量使用基础详解

    这篇文章主要为大家介绍了C语言注释和变量使用示例基础详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • 老生常谈C++ 中的继承

    老生常谈C++ 中的继承

    这篇文章主要介绍了C++ 中的继承,本文通过实例代码给大家介绍的非常详细对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • C语言详解strcmp函数的分析及实现

    C语言详解strcmp函数的分析及实现

    strcmp函数语法为“int strcmp(char *str1,char *str2)”,其作用是比较字符串str1和str2是否相同,如果相同则返回0,如果不同,前者大于后者则返回1,否则返回-1
    2022-05-05
  • C语言编程数据结构基础详解小白篇

    C语言编程数据结构基础详解小白篇

    这篇文章主要介绍了数据结构的基础,非常适合初学数据结构的小白,有需要的朋友可以借鉴参考下,希望可以有所帮助,祝大家多多进步,早日升职加薪
    2021-09-09

最新评论