智能指针的实现及原理 + Good ! 句柄类

C++智能指针深度解析:从RAII原理到多线程实战避坑 在C++编程中,内存管理是核心挑战之一,手动管理原始指针极易导致内存泄漏、野指针等问题。RAII(资源获取即初始化)作为一种关键编程范式,通过将资源生命周期与对象绑定,为资源管理提供了自动化解决方案。基于RAII理念,C++标准库设计了智能指针这一重要工具,它不仅能自动释放内存,更通过明确的所有权语义(独占、共享、观察)来规范资源管理逻辑,从而提升代码的健壮性和可维护性。智能指针在多线程环境下的引用计数原子操作、循环引用检测与解决等方面具有重要技术价值,广泛应用于大型项目开发、高性能服务、游戏引擎及嵌入式系 阅读详情

C++程序设计的一种常用技术——智能指针(smart pointer),主要内容包括引用计数(reference count)和句柄类(handle class)。 当类中有指针成员时,一般有两种方式来管理指针成员:一是采用值型的方式管理,每个类对象都保留一份指针指向的对象的拷贝;另一种更优雅的方式是使用智能指针,从而实现指针指向的对象的共享。

   智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。
 
   每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。
 
   实现引用计数有两种经典策略:一是引入辅助类,二是使用句柄类。下面分别介绍这些内容。
问题描述
   假设有一个名为TestPtr的类,里面有一个指针成员,简化为如下代码:

class TestPtr 
{
public:
    TestPtr(int *p): ptr(p) { }
    ~TestPtr( ) { delete ptr; }
    // other operations
private:
    int *ptr;
    // other data

};

 
在这种情况下,类TestPtr对象的任何拷贝、赋值操作都会使多个TestPtr对象共享相同的指针。但在一个对象发生析构时,指针指向的对象将被释放,从而可能引起悬垂指针。
   现在我们使用引用计数来解决这个问题,一个新的问题是引用计数放在哪里。显然,不能放在TestPtr类中,因为多个对象共享指针时无法同步更新引用计数。
方案一
   这里给出的解决方案是,定义一个单独的具体类(U_Ptr)来封装指针和相应的引用计数。由于这个类只是用于对类HasPtr中的成员指针ptr进行了封装,无其它用途,所以把引用计数类U_Ptr的所有成员均定义为private,并把类HasPtr声明为它的友元类,使HasPtr类可以访问U_Ptr类。例代码如下:
  1. #include <iostream>  
  2. using namespace std;  
  3. class U_Ptr {  // 计数类, 我们不希望普通用户使用,所以都为 private  
  4.     private :  
  5.         friend class HasPtr;  
  6.     private :  
  7.         U_Ptr(int *p) : ip(p), use(1) {}  
  8.         ~U_Ptr() {delete ip;}  
  9.   
  10.         int *ip;  
  11.         size_t use;  
  12. };  
  13. class HasPtr {  
  14.     public :  
  15.         HasPtr(int *p, int i) : ptr(new U_Ptr(p)), val(i) {}  
  16.         HasPtr(const HasPtr &orig) : ptr(orig.ptr), val(orig.val) {++ptr->use;}  
  17.         HasPtr& operator=(const HasPtr&);  
  18.         ~HasPtr() {  
  19.             if((--ptr->use) == 0) delete ptr;  
  20.         }  
  21.     private :  
  22.         U_Ptr *ptr;  
  23.         int val;  
  24. };  
  25. HasPtr& HasPtr::operator=(const HasPtr &rhs) {  
  26.     ++rhs.ptr->use;  
  27.     if(--ptr->use == 0) {  
  28.         delete ptr;  
  29.     }  
  30.     ptr = rhs.ptr;  
  31.     val = rhs.val;  
  32.     return *this;  
  33. }  
  34. int main() {  
  35.     return 0;  
  36. }  
   当希望每个HasPtr对象中的指针所指向的内容改变而不影响其它对象的指针所指向的内容时,可以在发生修改时,创建新的对象,并修改相应的引用计数。这种技术的一个实例就是写时拷贝(Copy-On-Write)。
这种方案的缺点是每个含有指针的类的实现代码中都要自己控制引用计数,比较繁琐。特别是当有多个这类指针时,维护引用计数比较困难。
方案二
   为了避免上面方案中每个使用指针的类自己去控制引用计数,可以用一个类把指针封装起来。封装好后,这个类对象可以出现在用户类使用指针的任何地方,表现为一个指针的行为。我们可以像指针一样使用它,而不用担心普通成员指针所带来的问题,我们把这样的类叫句柄类。在封装句柄类时,需要申请一个动态分配的引用计数空间,指针与引用计数分开存储。实现示例如下:
#include <iostream>
#include <stdexcept>
#define BUG cout << "here\n";
using namespace std;

#define TEST_SMARTPTR
class Stub {
public:
    void print() {
        cout<<"Stub: print"<<endl;
    }
    ~Stub(){
        cout<<"Stub: Destructor"<<endl;
    }
};

template <typename T>
class SmartPtr {
public:
    SmartPtr(T *p = 0): ptr(p), pUse(new size_t(1)) { }
    SmartPtr(const SmartPtr& src): ptr(src.ptr), pUse(src.pUse) {
        ++*pUse;
    }
    SmartPtr& operator= (const SmartPtr& rhs) {
        // self-assigning is also right
        ++*rhs.pUse;
        decrUse();
        ptr = rhs.ptr;
        pUse = rhs.pUse;
        return *this;
    }
    T *operator->() {
        if (ptr)
            return ptr;
        throw std::runtime_error("access through NULL pointer");
    }
    const T *operator->() const {
        if (ptr)
            return ptr;
        throw std::runtime_error("access through NULL pointer");
    }
    T &operator*() {
        if (ptr)
            return *ptr;
        throw std::runtime_error("dereference of NULL pointer");
    }
    const T &operator*() const {
        if (ptr)
            return *ptr;
        throw std::runtime_error("dereference of NULL pointer");
    }
    ~SmartPtr() {
        decrUse();
#ifdef TEST_SMARTPTR
        std::cout<<"SmartPtr: Destructor"<<std::endl; // for testing
#endif
    }

private:
    void decrUse() {
        --(*pUse); // 虚析构
        if (*pUse == 0) { //
            delete ptr;
            delete pUse;
        }
    }
    T *ptr;
    size_t *pUse;
};

int main() {
    try {
        SmartPtr<Stub> t;
        t->print();
    } catch (const exception& err) {
        cout << err.what() << endl;
    }
    BUG
    SmartPtr<Stub> t1(new Stub);
    SmartPtr<Stub> t2(t1);
    SmartPtr<Stub> t3(new Stub);
    BUG
    t3 = t2;
    BUG
    t1->print();
    BUG
    (*t3).print();

    return 0;
}


C++异常处理与智能指针:构建健壮程序的RAII与资源管理 在C++编程中,资源管理与错误处理是构建健壮、安全软件的核心基础。RAII(资源获取即初始化)作为一种关键设计理念,通过将资源生命周期与对象生命周期绑定,确保资源在作用域结束时自动释放,从而有效防止内存泄漏。异常处理机制则提供了一种结构化的错误处理方式,通过将错误检测与处理分离,避免了传统错误码导致的逻辑耦合与资源清理困难。这两项技术共同构成了现代C++工程实践的基石,广泛应用于高性能服务器、游戏引擎及嵌入式系统等场景,帮助开发者从编写“能运行”的代码升级到编写“健壮、安全、易维护”的工业级代码。本文深入探 阅读详情

相关推荐

C++智能指针循环引用:原理、诊断与weak_ptr解决方案

在C++内存管理中,智能指针通过引用计数机制实现自动化资源回收,是现代C++ RAII理念的核心实践。其核心原理是当对象的引用计数归零时自动释放内存,这一机制在复杂对象关系中可能引发循环引用问题,导致内存泄漏。循环引用会显著影响程序的内存使用效率与长期运行稳定性,尤其在服务端应用、游戏引擎等场景中危害巨大。通过引入std::weak_ptr这一弱引用工具,可以打破对象间的强引用闭环,有效解决内存泄漏问题。本文结合智能指针与内存泄漏等热词,深入剖析循环引用的形成机制与解决方案。

weixin_34274029的博客 312

c++智能指针实现

已知面试官常问c++大型程序内存泄露怎么办,同学们通常会回答使用智能指针,智能指针可以避免使用new来初始化对象带来的delete问题,智能指针的实现思路是raii思想。unique_ptr传入函数作为参数时无法通过值传递,但可以通过引用传递,另外,可以通过get方法获得裸指针传入,也可以使用move语义将智能指针交给函数管理。共享指针即一个对象可以由多个指针托管,当所有托管指针都不再托管该对象时,对象才会被析构,共享指针可以通过。与unique_ptr不同的是,shared_ptr有。

xianzhetime的博客 480

航测无人机las点云数据生成DEM

“ 做航测的同僚都知道,Pix4D或者CC(ContextCapture)都可以生成DSM,往往高程点提取以及土方计算都需要用到DEM,PhotoScan软件可以提出地面点并只应用地面点连接三角网,然而分类效果差,生成的DEM不管是平整度还是精度,都不理想。而传统等高线生DEM需要耗费较长时间,以下提供一种参考方法,供大家探讨。 ” 1 点云数据 航测类软件大多可以生成点云数据,如Pix4D,PhotoScan,CC等,此次点云数据为citymapper2相片基于CC生产的Las点云。 2 筛选地面点 筛.

qq_43173805的博客 1万+

C++:智能指针实现

weak_ptr不参与资源的管理和释放,可以使用shared_ptr对象来构造weak_ptr对象,但是不能直接使用指针来构造weak_ptr对象,在weak_ptr中,也没有operator*函数和operator->成员函数,不具有一般指针的行为,因此,weak_ptr严格意义上并不是智能指针,weak_ptr的出现,就是为了解决shared_ptr的循环引用问题。但是,只有对象本身析构,它的成员才会析构,因此n1和n2彼此制约对方的析构,最终n1和n2的资源都无法释放,造成了内存泄漏。

tecoes的博客 1586

UE5Could not be compiled. Try rebuilding from source manually.

UE5Could not be compiled. Try rebuilding from source manually.

weixin_45417260的博客 2770

扣子(coze)案例^第22期:零代码打造小红书竞品监控系统+AI自动生成运营策略建议

本文详细介绍了如何利用扣子(coze)平台零代码搭建小红书竞品监控系统。该系统通过自动化工作流抓取竞品笔记数据,并存入飞书多维表格,结合AI能力自动生成包含可视化分析报告在内的运营策略建议,帮助运营者高效进行数据驱动的市场分析。

weixin_29313239的博客 1004

c++智能指针(unique_ptr、shared_ptr)的简易实现

具体而言,就是这样,如下所示,当我们创建这个智能指针对象时,这个对象资源就被放在了栈上,当。而。

qq_58158950的博客 1859

嵌入式开发避坑指南:手把手教你用STM32CubeMX配置W9825G6KH SDRAM(含时序参数详解)

本文详细介绍了如何使用STM32CubeMX配置W9825G6KH SDRAM,包括硬件连接检查、CubeMX初始化步骤、时序参数优化及稳定性问题排查。通过实测波形分析和案例分享,帮助开发者避免常见配置错误,提升嵌入式系统性能与稳定性。

weixin_42542669的博客 197

C++智能指针原理与实现

如果一块内存被shared_ptr和weak_ptr同时引用,当所有shared_ptr析构了之后,不管还有没有weak_ptr引用该内存,内存也会被释放。unique_ptr在auto_ptr的基础上直接禁用了拷贝构造和赋值重载(delete),从而避免了auto_ptr在使用上容易出错的问题,但是没有了这两个函数,对于用户非常不便。weak_ptr是一个弱引用,它是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是说,它。

geek! 1524

【CTFSHOW】web入门 黑盒测试

文章目录写在前面web380web381web382web383web384web385web386web387web388web389web390web391web392web393web394web395参考资料 写在前面 一直没搞过渗透,先学学黑盒测试吧 web380 进入题目发现是一个关于灯泡的悲伤故事,点进去,看到跳转到page_1.php页面。 我们访问page.php试试: 发现报错:$id.php,可以猜想需要传名称为id的参数,来访问id.php。我们访问page.php?id=1试试

7ruth0hn的博客 1897

基于深度强化学习的柔性作业车间动态调度

在追求敏捷和灵活的生产调度方面,处理不可预测的动态事件的能力变得越来越重要。与此同时,生产系统中的网络-物理融合产生了大量需要实时挖掘和分析的工业数据。为了便于这种实时控制,本研究提出了一种分层分布式的体系结构来解决动态柔性作业车间调度问题。采用双深度Q网络算法(DDQN)训练调度智能体,捕捉生产信息与调度目标之间的关系,为具有恒定任务到达的柔性作业车间实时做出调度决策。为了处理动态调度中问题的可变规格说明,提出了专门的状态和动作表示法。此外,还提出了一种代理奖励整形技术(surrogate reward

太剧烈的快乐与太剧烈的悲哀是有相同之点的——同样地需要远离人群! 1万+

【C++】实现智能指针

【C++】实现智能指针

江湖人称菠萝包 1363

RK平台以太网设置中添加代理设置

以太网中配置Configuration的时候可以IpConfiguration的初始化函数来设置代理类型和代理参数。通过添加一个KEY_ETH_PROXY的选项来设置代理的配置,然后再设置以太网静态或者动态的类型时候下发给系统进行设置。

Android系统开发笔记 656

C++智能指针深度解析:从RAII原理到unique_ptr、shared_ptr实战应用

在C++编程中,内存管理是开发者面临的核心挑战之一,手动管理内存容易导致内存泄漏和悬空指针等问题。RAII(Resource Acquisition Is Initialization)作为一种重要的资源管理范式,通过将资源生命周期与对象生命周期绑定,为自动内存管理提供了理论基础。基于RAII原理,智能指针技术应运而生,它通过封装裸指针并在析构时自动释放资源,显著提升了代码的安全性和可维护性。智能指针在现代C++开发中具有重要价值,特别是在大型项目和高性能场景下,能有效减少内存相关错误。常见的智能指针包括s

android_mylove的专栏 417

RISC-V CPU设计(三)---多周期CPU的设计与实现

基本情况 本多周期CPU支持RV32I指令集(fence,ecall,ebreak除外),已通过部分指令的测试,如代码有bug,欢迎指出。 模块划分 代码将CPU划分为以下几个模块: 1.控制单元:ControlUnit 用于产生控制信号,是CPU的大脑,指挥中枢。 2.分支决策单元:BranchUnit 用于决定B型指令是否发生跳转 3.立即数单元:ImmUnit 用于从指令中解析出立即数. 4.寄存器堆:RegisterFile RISC-V的32个寄存器,其中x0寄存器恒为0,不可更改。 5.指令存储

qq_40268672的博客 5542

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

C++11智能指针深度解析:从RAII原理到unique_ptr、shared_ptr实战避坑

在C++编程中,动态内存管理是核心且易错的环节,手动new/delete常导致内存泄漏和悬垂指针。RAII(资源获取即初始化)是解决这一问题的关键设计范式,它将资源生命周期与对象生命周期绑定,确保资源自动释放。智能指针作为RAII思想的典型实现,通过封装裸指针和自动管理释放逻辑,极大提升了代码的健壮性和安全性。从技术价值看,智能指针不仅减少了内存错误,还明确了资源所有权语义,是现代C++编写异常安全代码的基础。在实际应用场景中,unique_ptr适用于独占资源管理,shared_ptr用于共享所有权,we

fanjava 430

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

C++智能指针完全指南:从unique_ptr到shared_ptr的内存管理实践

在C++编程中,内存管理是核心挑战之一,手动管理内存容易导致内存泄漏、悬空指针等问题。RAII(资源获取即初始化)是解决这一问题的关键设计理念,通过将资源生命周期与对象生命周期绑定,实现资源的自动管理。智能指针作为RAII理念的具体实现,提供了自动化内存管理的技术方案,能够显著提升代码的健壮性和可维护性。其中,std::unique_ptr实现了独占所有权模型,适用于单一所有者的场景;std::shared_ptr通过引用计数机制支持共享所有权,而std::weak_ptr则用于解决循环引用问题。这些工具在

weixin_33841503的博客 421

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

C++智能指针与RAII:现代C++资源管理的核心范式

在C++编程中,资源管理是确保程序稳定性和性能的关键环节。RAII(Resource Acquisition Is Initialization)作为一种核心编程范式,通过将资源的生命周期与对象的生命周期绑定,实现了资源的自动管理。其原理在于利用栈上对象析构函数自动调用的特性,将资源释放的责任转移给语言机制,从而保障异常安全。这一模式的技术价值在于从根本上避免了内存泄漏、文件句柄未关闭等常见问题,提升了代码的健壮性。智能指针是RAII思想在动态内存管理领域的经典应用,它通过明确的所有权语义(如独占、共享)来

weixin_33462167的博客 266

C++智能指针循环引用:原理、诊断与四大破解策略

在C++现代编程中,智能指针是管理动态内存、防止内存泄漏的核心工具。其基于引用计数的原理,通过自动跟踪对象被引用的次数来决定何时释放内存,极大地提升了开发效率和代码安全性。然而,当多个对象通过shared_ptr相互引用形成闭环时,引用计数无法归零,就会导致内存无法释放,这就是循环引用问题。这一问题的技术价值在于,它揭示了单纯依赖引用计数的局限性,促使开发者深入思考对象间的所有权关系。在实际应用场景中,如游戏引擎的对象管理、GUI框架的组件关系或观察者模式,循环引用尤为常见。本文以C++智能指针为切入点,深

301

C++异常处理与智能指针:RAII机制下的内存安全与健壮代码实践

在C++编程中,内存管理与错误处理是构建健壮、安全软件的核心基础。传统手动管理内存(new/delete)和错误码返回的方式,极易导致内存泄漏、悬空指针等问题,尤其在复杂项目或异常发生时。RAII(资源获取即初始化)作为一种关键编程范式,通过将资源生命周期与对象生命周期绑定,确保资源在作用域结束时自动释放,从而从根本上杜绝资源泄漏。智能指针(如unique_ptr、shared_ptr)是RAII思想的典型实现,它们自动化了动态内存管理,unique_ptr提供独占所有权,shared_ptr通过引用计数实

weixin_34088583的博客 653

C++内存安全实战:用移动语义与智能指针彻底告别深拷贝陷阱和内存泄漏

让正确的事更容易,让错误的事更难发生。通过合理使用智能指针和移动语义,你不仅能彻底规避内存泄漏和深拷贝陷阱,还能写出更高效、更安全、更易维护的代码。🚀记住不要裸露new,除非你在封装 RAII 类;能移动就别拷贝;让编译器和标准库替你管理内存!从此,C++ 内存管理不再是噩梦,而是你手中的利器。

2603_94941239的博客 296

现代C++高性能编程实战:智能指针与并发容器深度解析

在C++编程中,内存管理与并发控制是构建高性能、高可靠性系统的核心挑战。RAII(资源获取即初始化)是现代C++资源管理的核心理念,它通过对象的生命周期自动管理资源,从根本上避免了资源泄漏。智能指针(如unique_ptr、shared_ptr)是RAII思想的典型实践,通过所有权语义自动管理动态内存,显著提升了代码的安全性。在多线程环境下,数据竞争和死锁是常见问题,需要借助同步原语和并发编程模型来保证数据一致性。C++标准库提供了原子操作、互斥锁、条件变量等工具,而并发容器(如线程安全队列)则封装了这些细

chutisun0039的博客 328

深入解析C++智能指针:从unique_ptr到shared_ptr的性能与场景选择

本文深入解析C++智能指针,重点对比unique_ptr和shared_ptr的性能差异与适用场景。通过实际案例展示unique_ptr在独占资源管理中的高效性,以及shared_ptr在共享所有权时的引用计数机制与潜在性能损耗,帮助开发者根据具体需求选择最合适的智能指针类型,提升代码安全性与执行效率。

weixin_28049429的博客 392

C++智能指针:RAII机制与内存管理实战指南

在C++编程中,内存管理是核心且易错的技术领域,涉及动态内存分配与释放。RAII(Resource Acquisition Is Initialization)是一种关键编程范式,它将资源生命周期与对象生命周期绑定,确保资源在对象销毁时自动释放,从而避免内存泄漏和悬空指针。这一原理催生了智能指针技术,它通过封装原始指针并自动管理内存,显著提升了代码的安全性与可维护性。智能指针在大型项目、多线程环境及资源受限系统中具有重要价值,广泛应用于对象生命周期管理、资源自动清理等场景。本文聚焦于智能指针实现,深入解析s

weixin_34377919的博客 347
上一篇: poj 2255 给前序中序写后序 [ 也是经典的面试题 ]
下一篇: C++ this 指针详解 [ c++中文网 ]
aclay
博客等级 码龄15年 37粉丝 177原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值