C++简单实现shared_ptr的代码

实现一个简单的shared_ptr需要考虑以下几个方面:

1.计数器实现:将指针的计数器放在一个自定义类中,当有多个shared_ptr指向同一个对象时,计数器加1;当一个指针被销毁时,计数器减1;当计数器为0时,释放对象所占用的内存。

2.拷贝构造函数和赋值运算符实现:在拷贝构造函数和赋值运算符中,需要将新对象的计数器指向原对象的计数器,使得两个对象指向同一个计数器。同时,需要保证原计数器的值加1,新计数器的值等于原计数器的值。

以下是实现shared_ptr的示例代码:

template<typename T>
class shared_ptr {
public:
  // 构造函数
  shared_ptr(T* ptr = nullptr) {
    if (ptr) {
      data = new Counter(ptr);
    }
  }

  // 拷贝构造函数
  shared_ptr(const shared_ptr<T>& ptr) {
    data = ptr.data;
    if (data) {
      data->counter++;
    }
  }

  // 赋值运算符
  shared_ptr<T>& operator=(const shared_ptr<T>& ptr) {
    if (this != &ptr) {
      release();
      data = ptr.data;
      if (data) {
        data->counter++;
      }
    }
    return *this;
  }

  // 重载*运算符
  T& operator*() const {
    return *(data->ptr);
  }

  // 重载->运算符
  T* operator->() const {
    return data->ptr;
  }

  // 获取计数器
  int use_count() const {
    if (data) {
      return data->counter;
    } else {
      return 0;
    }
  }

  // 释放指针,如果计数器为0,则删除对象
  void release() {
    if (data) {
      data->counter--;
      if (data->counter == 0) {
        delete data;
      }
    }
    data = nullptr;
  }

  // 析构函数
  ~shared_ptr() {
    release();
  }
private:
  struct Counter {
    Counter(T* p = nullptr) : ptr(p), counter(1) {}
    ~Counter() { delete ptr; }
    T* ptr;
    int counter;
  };
  Counter* data;
};

示例1:使用shared_ptr共享指针

#include <iostream>
#include "shared_ptr.h"

class MyClass {
public:
    MyClass() { std::cout << "MyClass()" << std::endl; }
    ~MyClass() { std::cout << "~MyClass()" << std::endl; }
};

int main() {
    shared_ptr<MyClass> p1(new MyClass); // 创建p1
    shared_ptr<MyClass> p2(p1); // 复制构造函数,p1、p2计数器都为2
    std::cout << "p1 use_count: " << p1.use_count() << std::endl; 
    std::cout << "p2 use_count: " << p2.use_count() << std::endl; 
    shared_ptr<MyClass> p3 = p1; // 赋值运算符,p1、p2、p3计数器都为3
    std::cout << "p1 use_count: " << p1.use_count() << std::endl; 
    std::cout << "p2 use_count: " << p2.use_count() << std::endl; 
    std::cout << "p3 use_count: " << p3.use_count() << std::endl; 
    return 0; // 离开作用域,p1、p2、p3计数器都为0,MyClass会被自动释放
}

输出:

MyClass()
p1 use_count: 2
p2 use_count: 2
p1 use_count: 3
p2 use_count: 3
p3 use_count: 3
~MyClass()

示例2:shared_ptr数组

#include <iostream>
#include "shared_ptr.h"

class MyClass {
public:
    MyClass(int n) : data(new int[n]) { std::cout << "MyClass()" << std::endl; }
    ~MyClass() { delete[] data; std::cout << "~MyClass()" << std::endl; }
    int* data;
};

int main() {
    shared_ptr<MyClass[]> p1(new MyClass[3](5)); // 创建包含3个MyClass对象的数组
    std::cout << "p1[1].data[2]: " << p1[1].data[2] << std::endl; // 访问数组
    return 0; // 离开作用域,MyClass数组会被自动释放
}

输出:

MyClass()
MyClass()
MyClass()
p1[1].data[2]: 5
~MyClass()
~MyClass()
~MyClass()

这里需要注意的是,shared_ptr的数组版本需要将单个类型的模板参数改为数组类型的模板参数,然后通过重载下标运算符来访问数组元素。同时,数组需要使用new[]开辟空间,使用delete[]释放空间。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++简单实现shared_ptr的代码 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • Visual Studio 如何创建C/C++项目问题

    当您需要使用 Visual Studio 进行 C/C++ 项目开发时,可以按照以下步骤创建项目: 打开 Visual Studio 并选择“文件”->“新建”->“项目”,可以看到“新建项目”对话框。 在“新建项目”对话框中,您可以选择“Visual C++”类别,并选择“空项目”模板。然后,您可以输入项目名称和保存位置,最后单击“创建”按钮。…

    C 2023年5月23日
    00
  • C++如何去除cpp文件的注释详解

    当我们在编写C++代码时,有时候会添加一些注释来方便代码的阅读和理解,但是在实际编译的时候,注释是没有用处的,只会占用编译时间和程序空间。因此需要去除cpp文件中的注释。下面提供两种方法。 方法一:正则表达式 正则表达式是一种高效的文本搜索和处理工具。可以通过正则表达式匹配出注释,并将其删除。 使用文本编辑器,打开需要去除注释的cpp文件。 使用文本编辑器的…

    C 2023年5月23日
    00
  • Excel如何使用组合函数combin

    Excel如何使用组合函数COMBIN comibn函数的作用 COMBIN函数用于计算从一组n个元素中选择r个元素的组合数。其数学公式为: COMBIN(n, r) = n!/((n-r)!*r!) 其中, n为总元素数,r为选中元素数. COMBIN函数的使用方法 COMBIN函数的语法为: COMBIN(number, number_chosen) 参…

    C 2023年5月22日
    00
  • jQuery使用getJSON方法获取json数据完整示例

    下面是关于”jQuery使用getJSON方法获取json数据完整示例”的完整攻略: 1. 简介 在Web开发中,经常需要使用Ajax技术从服务器获取数据并进行显示或其他操作。其中,获取的数据可能是JSON格式的数据,应对这种需求,jQuery提供了一个getJSON()方法来处理JSON数据。 2. getJSON()方法说明 方法语法 $.getJSON…

    C 2023年5月23日
    00
  • 详解C语言之预处理(下)

    下面是“详解C语言之预处理(下)”的完整攻略。 理解C语言中的宏定义 在C语言中,宏定义是一种预处理指令,可以在编译代码前将它们替换为指定的代码片段。这个过程称为宏展开。宏定义的语法格式如下: #define 宏名 宏体 其中,宏名是由字母、数字和下划线组成的标识符,不能以数字开头,而宏体是要替换的代码片段。宏定义还可以带有参数,这种宏定义称为带参数的宏定义…

    C 2023年5月22日
    00
  • C语言文字艺术之数据输入输出

    下面是“C语言文字艺术之数据输入输出”的完整攻略: 1. 数据输入输出的基本操作 在C语言中,我们可以使用printf函数将数据输出到屏幕上,使用scanf函数获取用户输入的数据。 #include <stdio.h> int main() { int num; printf("请输入一个整数:"); scanf("…

    C 2023年5月23日
    00
  • 如何给随机数加密

    下面是如何给随机数加密的完整攻略,共分为以下几个步骤: 步骤一:生成随机数 首先需要生成一个随机数,可以使用编程语言自带的随机数生成器函数或第三方库生成。注意,生成的随机数应该具有高度的随机性和不可预测性。 这里以 PHP 语言为例,使用 random_int() 函数生成一个 0 到 100 的随机整数: $random_num = random_int(…

    C 2023年5月23日
    00
  • 一文详解Node中的文件模块与核心模块

    一文详解Node中的文件模块与核心模块 模块的概念和分类 在 Node.js 中,所有的功能都是通过模块来实现的。模块是 Node.js 应用程序的基本组成部分,文件和模块是一一对应的。 Node.js 中有两种模块:核心模块(built-in core module)和文件模块(file module)。核心模块是 Node.js 自带的模块,文件模块是用…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部