智能指针

智能指针是当我们在使用对象时,有时会把对象的内存分配在堆上忘记释放,导致内存泄露,并且当多个指针共享同一个对象的内存时,容易出现重复释放内存,导致错误。

我们针对所需要共享的对象,手动完成一个智能指针类来代替该类别的指针,自动帮我们释放内存,共享内存。以一个共享Object类的对象数据来说明两个版本的共享指针的实现。

class Object {
public:
int a;
int b;
};

基本版本的智能指针

以下为一个最简单版本的智能指针,利用自动调用析构函数来调用delete函数,释放内存。但该智能指针不能实现引用计数来共享内存,只能帮我们管理单个对象内存的自动释放。

/* version1 of smartpointer*/
class SmartPointer {
public:
SmartPointer(Object* p) {
cout<<"get pointer"<<endl;
ptr = p;
}
~SmartPointer() {
cout<<"free memory"<<endl;
delete ptr;
}
private:
Object *ptr;
}; void process(SmartPointer &p) {
//void process(SmartPointer &p) {
cout<<"processing..."<<endl;
}

使用方法

int main() {
SmartPointer P(new Object);
process(p);
return 0;
}

增加版本的智能指针

当多个智能指针指向同一段内存时, 我们需要加强我们的智能指针的功能:

  • 引用计数:记录当前有多少个指针指向共享对象
  • 当引用计数为0时,释放共享对象内存
  • 构造函数与赋值构造函数的实现
  • 箭头运算符->与解引用运算符*的重载

为了更加智能的管理引用计数与共享内存,我们实现Counter类帮我们的智能指针管理。指向同一个共享对象的智能指针共享同一个Counter对象。关系如下:

class Counter {
// SmartPointerPro设置为友元,否则smartpointerpro内部不能访问私有成员cnt与ptr
friend class SmartPointerPro;
public:
Counter() {
ptr = NULL;
cnt = 0;
}
Counter(Object *p) {
ptr = p;
cnt = 1;
}
~Counter() {
delete ptr;
}
private:
Object *ptr;
int cnt;
};

下面是增加版本智能指针的实现

/* version2 of smartpointer: need a counter class to count shared times*/
class SmartPointerPro {
public:
// 当对像传入时,需要初始化一个counter来记录该对象共享次数
SmartPointerPro(Object *p) {
ptr_counter = new Counter(p);
}
// 用一个smartpointer来初始化另一个smartpointer,counter中共享次数+1
SmartPointerPro(const SmartPointerPro &sp) {
ptr_counter = sp.ptr_counter;
++ptr_counter->cnt;
}
// 相互赋值时:等号左边的对象被覆盖,cnt减一,等号右边对象共享次数加一
SmartPointerPro& operator=(const SmartPointerPro &sp) {
++sp.ptr_counter->cnt;
--ptr_counter->cnt;
if (ptr_counter->cnt == 0) {
delete ptr_counter;
}
ptr_counter = sp.ptr_counter;
}
~SmartPointerPro() {
--ptr_counter->cnt;
if (ptr_counter->cnt == 0) {
delete ptr_counter;
}
}
Object *operator->() {
return ptr_counter->ptr;
}
// 返回值为引用型,说明解引用后直接可以调用其它操作
Object &operator*() {
return *(ptr_counter->ptr);
}
private:
Counter *ptr_counter;
};

增加版智能指针使用方法

int main() {
SmartPointerPro p(new Object());
p->a = 10;
p->b = 20;
int a_val = (*p).a;
int b_val = (*p).b;
cout<<"p->a, p->b, a_val, b_val: "
<<p->a<<" "<<p->b<<" "<<a_val<<" "<<b_val<<" "<<endl;
SmartPointerPro q(p);
cout<<"q->a, q->b: "<<q->a<<" "<<q->b<<endl;
return 0;
}

系统实现的智能指针

以上增加版本的智能指针看起来很好用,但是每次使用都需要先定义SmartPointerPro与Counter类,那么有没有系统库可以调用呢?答案是肯定的,但是需要我们先安装boost库。安装之后,

#include <boost::shared_ptr>

就可以使用系统实现的智能指针了,系统版本实现原理与我们增加版本智能指针原理基本相同。具体使用方法参考

参考

chapter-nine

[C++]智能指针的实现与使用的更多相关文章

  1. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  2. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  3. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  4. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  5. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  6. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

  7. 基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  8. C++ 引用计数技术及智能指针的简单实现

    一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...

  9. C++11智能指针读书笔记;

    智能指针是一个类对象,而非一个指针对象. 原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 它的一种通用实现 ...

  10. 「C++」理解智能指针

    维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...

随机推荐

  1. 移动应用/APP的测试流程及方法

    1. APP测试基本流程 1.1流程图 1.2测试周期 测试周期可按项目的开发周期来确定测试时间,一般测试时间为两三周(即15个工作日),根据项目情况以及版本质量可适当缩短或延长测试时间.正式测试前先 ...

  2. 基于NIO的Netty网络框架

    Netty是一个高性能.异步事件驱动的NIO框架,它提供了对TCP.UDP和文件传输的支持,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者 ...

  3. java基础(二章)

    java基础(二章) 一,变量 1.变量是内存中的一个标识符号,用于存储数据 2.变量命名规则 l  必须以字母.下划线 _ .美元符号 $ 开头 l  变量中,可以包括数字 l  变量中,不能出现特 ...

  4. C++ #if #endif #define #ifdef #ifndef #if defined #if !defined详解 (转)

    (源)http://blog.csdn.net/sky1203850702/article/details/42024673 首先,让我们先从头文件开始,在很多头文件里,我们会看到这样的语句 #ifn ...

  5. JavaScript中对事件简单的理解(2)

    事件(event) event对象 (1)什么是event对象? Event 对象代表事件的状态,比如事件在其中发生的元素.键盘按键的状态.鼠标的位置.鼠标按钮的状态.事件通常与函数结合使用,函数不会 ...

  6. iframe实现自适应高度

    代码简单,兼容性还可以 <script>function SetWinHeight(obj) {  var win=obj;  if (document.getElementById)   ...

  7. thinkphp5.0学习笔记(四)数据库的操作

    ThinkPHP内置了抽象数据库访问层,把不同的数据库操作封装起来,我们只需要使用公共的Db类进行操作,而无需针对不同的数据库写不同的代码和底层实现,Db类会自动调用相应的数据库驱动来处理.采用PDO ...

  8. Python os模块--路径、文件、系统命令等操作

    os模块包含普遍的操作系统功能. 注意:函数参数path是文件或目录的路径,filename是文件的路径,dirname是目录的路径,路径可以是相对路径,也可绝对路径 常见或重要的函数为加粗字体 os ...

  9. 如何在BCGControlBar界面库的CBCGPFormView子视图里面添加工具栏

    最近有一个项目需求,需要在子视图里面添加一个新工具栏用来处理当前视图对应模块的操作.之前在对话框模式下做过添加工具栏的实现,在CBCGPFormView中添加工具栏还是头一次.在这里记录一下,给自己留 ...

  10. react实现双向绑定

    双向绑定功能是在项目中比较常见的一个需求,传统的js实现方式是添加监听函数的方式,Vue框架实现很简单,因为它本身就是基于双向绑定实现的,接下来我将讲解一下如何使用react实现双向绑定的功能是 首先 ...