新闻中心

C++如何实现一个智能指针_手动实现C++ shared_ptr的引用计数功能

2025-12-01
浏览次数:
返回列表
答案:实现简易 shared_ptr 需定义引用计数控制块,通过构造、拷贝、赋值和析构操作管理资源;1. 使用 int* 动态记录引用计数,多个指针共享同一块内存;2. 拷贝时递增计数,析构或赋值时调用 release 函数递减,为 0 则 delete 资源;3. 支持解引用、get、use_count 等接口;4. 示例验证了构造、作用域析构、赋值等场景下引用计数正确变化;5. 关键点包括独立分配计数、自赋值保护、reset 正确释放旧资源;6. 局限性有非线程安全、无自定义删除器、未优化内存布局,生产环境需改进。

c++如何实现一个智能指针_手动实现c++ shared_ptr的引用计数功能

实现一个简易的 shared_ptr 智能指针,核心是模拟引用计数机制,确保多个指针共享同一块内存时,只有最后一个指针释放时才真正 delete 资源。下面是一个手动实现的基本版本,包含构造、拷贝、赋值和析构等关键操作。

1. 定义引用计数控制块

我们需要一个额外的结构体来管理原始指针和引用计数,这个结构体被所有共享该对象的智能指针共用。

template <typename T>
class SharedPtr {
private:
    T* ptr;                    // 指向实际数据的指针
    int* ref_count;            // 指向引用计数的指针
<pre class='brush:php;toolbar:false;'>void release() {
    if (ref_count && --(*ref_count) == 0) {
        delete ptr;
        delete ref_count;
        ptr = nullptr;
        ref_count = nullptr;
    }
}

public: // 构造函数:接管原始指针 explicit SharedPtr(T* p = nullptr) : ptr(p), ref_count(nullptr) { if (ptr) { ref_count = new int(1); } }

// 拷贝构造函数
SharedPtr(const SharedPtr& other) : ptr(other.ptr), ref_count(other.ref_count) {
    if (ref_count) {
        ++(*ref_count);
    }
}

// 拷贝赋值运算符
SharedPtr& operator=(const SharedPtr& other) {
    if (this != &other) {
        release();  // 释放当前资源
        ptr = other.ptr;
        ref_count = other.ref_count;
        if (ref_count) {
            ++(*ref_count);
        }
    }
    return *this;
}

// 析构函数
~SharedPtr() {
    release();
}

// 解引用
T& operator*() const { return *ptr; }
T* operator->() const { return ptr; }

// 获取原始指针
T* get() const { return ptr; }

// 获取引用计数(调试用)
int use_count() const { return ref_count ? *ref_count : 0; }

// 判断是否唯一拥有
bool unique() const { return use_count() == 1; }

// 重置指针
void reset(T* p = nullptr) {
    release();
    ptr = p;
    if (ptr) {
        ref_count = new int(1);
    } else {
        ref_count = nullptr;
    }
}

};

2. 使用示例

测试我们实现的 SharedPtr 是否正确管理引用计数。

#include <iostream>
<p>struct MyClass {
int value;
MyClass(int v) : value(v) { std::cout << "MyClass(" << v << ") created\n"; }
~MyClass() { std::cout << "MyClass destroyed\n"; }
};</p><p>int main() {
SharedPtr<MyClass> sp1(new MyClass(42));
std::cout << "use count: " << sp1.use_count() << "\n";</p><pre class='brush:php;toolbar:false;'>{
    SharedPtr<MyClass> sp2 = sp1;
    std::cout << "use count after copy: " << sp1.use_count() << "\n";
} // sp2 析构,引用计数减一

std::cout << "use count after sp2 destroyed: " << sp1.use_count() << "\n";

SharedPtr<MyClass> sp3;
sp3 = sp1; // 赋值测试
std::cout << "use count after assignment: " << sp1.use_count() << "\n";

return 0;

}

Seede AI Seede AI

AI 驱动的设计工具

Seede AI 713 查看详情 Seede AI

3. 关键点说明

这个简易实现展示了 shared_ptr 的核心思想:

  • 引用计数独立分配:使用 int* 动态分配计数,确保多个实例共享同一个计数值。
  • release 函数:在析构和赋值时调用,负责递减计数并清理资源。
  • 自赋值保护:赋值前检查 this != &other,避免错误释放。
  • reset 方法:允许智能指针切换到新对象,并正确处理旧资源。

4. 局限性与改进方向

此实现是教学性质的简化版,生产环境的 shared_ptr 还需考虑:

  • 线程安全:多线程下引用计数应使用原子操作(如 std::atomic)。
  • 支持自定义删除器(deleter)。
  • weak_ptr 配合避免循环引用。
  • 性能优化:比如控制块与对象一起分配,减少内存碎片。

基本上就这些。理解引用计数的生命周期管理,是掌握智能指针的关键。

以上就是C++如何实现一个智能指针_手动实现C++ shared_ptr的引用计数功能的详细内容,更多请关注其它相关文章!


# c++  # ios  # stream  # ai  # 采药通网站推广好做吗  # 东营企业seo服务  # 企通网站建设  # 广州网站方案建设书  # 沈阳网站seo排名公司推荐  # 长治网站推广排名  # 专注福州seo价位多少  # 名优营销推广咨询电话  # 游戏公众号怎么营销推广  # 网站建设与博客  # 解决问题  # 中文网  # 相关文章  # 数独  # 是一个  # 如何用  # 自定义  # 多线程  # 多个  # 如何实现  # red  # 作用域 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: Python实时数据流中的动态最值查找策略  Excel Power Pivot如何处理XML数据源 构建高级数据模型  微信网页版官方快速登录入口 微信网页版网页版账号直达  163邮箱注册官网 免费申请163个人邮箱  蛙漫限时开放最深处链接_蛙漫全站漫画会员同款秒开地址  汽水音乐在线版入口_汽水音乐网页播放手册  如何在低配置电脑上搭建轻量级J*a环境_占用更小的环境选择技巧  sublime怎么进行远程开发编辑_配置rsub/rmate实现sublime编辑服务器文件  yy漫画网页版官方入口_yy漫画官网登录页面链接  打开就能玩的植物大战僵尸 植物大战僵尸网页版传送门  如何有效阻止外部脚本意外修改内联样式的高度属性  C++如何操作大型数据集_使用C++流式处理(Streaming)技术避免一次性加载大文件  c++项目目录结构应该如何组织_c++工程化项目结构规范  解决macOS上安装pyhdf时‘hdf.h’文件缺失的编译错误  C++如何进行游戏物理模拟_使用Box2D库为C++游戏添加2D物理效果  C++如何连接MySQL数据库_C++使用Connector/C++操作MySQL数据库教程  C#使用XPath查询节点时出错? 常见语法错误与调试技巧  如何在更新Composer依赖后自动运行测试_使用post-update-cmd钩子触发PHPUnit  如何使用spryker/configurable-bundles-products-resource-relationship模块解决复杂产品捆绑关系难题  Composer的 "check-platform-reqs" 命令有什么用_在部署前检查生产环境是否满足Composer依赖需求  内存疯狂猛猛涨价:主板销量直接腰斩!  必由学网页版入口 必由学官方平台直接访问  内存检查:在VS Code中调试C++时的内存视图  J*a中实现Go语言select通道多路复用机制  4399免费游戏网址入口 4399小游戏免费入口点开即玩  steam官方网页快速访问 steam账号注册全流程  零跑汽车11月交付量达70327台 实现连续9个月正增长  如何使用Rector自动化升级旧代码_通过Composer安装和配置Rector进行代码重构  火狐浏览器占用内存高卡顿怎么办 火狐浏览器性能优化设置技巧  将HTML Canvas内容转换为可上传的图像文件(File对象)  利用5118提升短视频内容效果_5118短视频关键词优化方法  利用Bokeh CustomJS动态控制DataTable列可见性  优化LangChain文档加载与ChromaDB集成:解决多文档处理与分块问题  拼多多购物车商品数量无法修改如何处理 拼多多购物车操作优化方法  KFC早餐时段怎么领特惠代码_KFC早餐订餐优惠代码获取与使用说明  蛙漫漫画免费阅读入口_蛙漫官方正版无广告纯净版  Golang并发任务中错误如何聚合_Golang goroutine error收集方式  在Qt QML中通过Python字典动态更新TextEdit内容的教程  C++指针和引用有什么区别_C++内存管理核心概念深度解析  MAC怎么让Dock栏只显示当前运行的应用_MAC终端命令实现极简Dock栏  在J*a中如何在J*a中使用异常机制记录错误日志_异常日志实践经验  LINQ to XML为何解析失败? 深入理解C# XDocument的异常处理  我的世界官方游戏入口 我的世界官网平台直达链接  提升Kafka消费者健壮性:会话超时处理与消息处理语义  实现全屏滚动与导航点:专业教程  Python中高效访问嵌套字典与列表中的键值对  拼多多视频播放卡顿如何处理 拼多多视频播放优化技巧  PHP中SSG-WSG API的AES加密实践:正确使用初始化向量  初次安装JDK时环境变量如何正确配置_J*A_HOME与PATH设置规则讲解  win11专注助手在哪 Win11免打扰模式设置与自动化规则【指南】 

搜索