博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
细说智能指针
阅读量:6989 次
发布时间:2019-06-27

本文共 5123 字,大约阅读时间需要 17 分钟。

提到指针,我们就会想到指针的高效,当然,滥用指针也会为我们带来许多的潜在bug。

提到指针,我们就会想到内存泄漏。比如,使用指针后忘记释放,久而久之,堆空间就会全部使用完,那么会带来很大的危害。再比如,两个指针指向同一片内存区域,我们对同一片区域进行了多次释放,同样会造成内存泄漏。
为了方便大家的理解,我们先来模拟一下,使用指针却忘记释放带来的危害。首先,我们要定义一个类。这次,还是定义女朋友类吧(之前写过一篇《细说C++的友元》用的就是女朋友类,这次还用这个吧,方便说明问题,更何况我们这群码畜怎么会有女朋友呢,没有女朋友只能自己创建了,哈哈哈哈)。
女生都喜欢自拍,尤其是漂亮的女生。所以,女生会有很多照片,对吧。那么,我们创建的这个女朋友类,就让她有照片吧。当然了,你女朋友的照片肯定不会随便给别人的吧,所以要把picutre这个变量声明为private类型。既然,女生喜欢自拍,并且发朋友圈,也就是说,其他人虽然得不到她的照片,却可以通过她的朋友圈看到她的自拍,也就意味着我们可以通过一个public函数访问picture这个变量。那么,我们现在来写代码。

class Girlfriend{private:    int pictures;public:    Girlfriend ( int i ){        cout << "Girlfriend ( int i ) " << endl;   /*这句代码是不需要的,        写在这里只是为了后期能够方便我们观察        */        this->pictures = i;    }    int getPic ( void ){        return this->pictures;    }    ~Girlfriend (){        cout << "~Girlfriend() " << endl;  /*这句代码是不需要的,        写在这里只是方便我们观察        */    }};

接着,我们来写一个主函数,来使用这个女朋友类。

int main ( int argc, char** argv ){    Girlfriend* Alice = new Girlfriend( 100 );    cout << "my girlfriend's pictures are " << mp->getPic() << endl;    system ( "pause" );    return 0;}

运行结果:

细说智能指针
我们在主函数中做了什么事情呢?我们通过指针动态创建了一个对象,并且,我创建的这个女朋友Alice有100张照片。看到这里,很多人就会想,指针危险吗?好像没什么危险啊。不是使用正常吗,看到程序运行结果,程序不是完美的执行了嘛,好像也没什么。
首先,我们创建的这个指针Alice没有去释放,仅仅创建了一个,危害不大,但是多了之后呢。那比如,我们现在再来写一个主函数。

int main ( int argc, char** argv ){    Girlfriend* Alice = new Girlfriend( 100 );    Girlfriend* Lisa = new Girlfriend( 200 );    cout << "my girlfriend Alice's pictures are " << Alice->getPic() << endl;    cout << "my girlfriend Lisa's pictures are " << Lisa->getPic() << endl;    system ( "pause" );    return 0;}

运行结果:

细说智能指针
我们先抛开指针不谈。我们就来谈谈女朋友。假如Alice是你女朋友,你手机里有她的100张照片,后来你们因为一些事情产生了矛盾分手了,于是你交了另外一个女朋友Lisa。有一次,Lisa翻你的手机,发现你竟然有100张前女友照片,她什么感受,估计要疯了,你说后果严不严重,所以,趁你的现女友没发现之前,赶紧把前女友照片给删了,赶紧把前女友照片释放掉,不然,后果……
现在,回归正题,我们使用指针创建对象,一个,两个,都没问题,那如果多了呢?100个,1000个,10000个,那内存还能受的了吗?所以,用完指针之后一定要释放指针。
但是,我们是人啊,不是机器,总会有遗忘的时候,那么我们有没有办法在指针使用完毕后,它自己释放呢?当有了这个需求后,我们就要开始思考解决办法了。很快,我们就有了解决方案:通过类对象模拟指针。指针有两个运算符,一个是->,另一个是星号,只要在类内重载这两个操作符就行了。那么,这个类的成员变量是什么呢?就是一个指针。通过类来模拟指针的,这就是智能指针了。现在,我们先来写一个简陋版的。

class SmartPointer{private:    Girlfriend* sp;public:    SmartPointer ( Girlfriend* p = NULL ){        sp = p;    }    Girlfriend* operator -> (){        return sp;    }    Girlfriend& operator * (){        return *sp;    }    ~SmartPointer (){        delete sp;        cout << "~SmartPointer() " << endl;  /*这句代码完全没必要,        写在这里只是便于我们观察            */    }}

我们在这个智能指针类中,重载指针了指针的两个运算符。通过这样做,我们解决了使用完毕指针后自动释放的问题。那么,还有一个问题,如果两个指针指向同一片区域,这样在释放指针时也会造成内存泄漏,因为同一片区域被释放两次。这个问题怎么解决呢?通过重载拷贝构造函数和赋值操作符。我们现在类内实现拷贝构造函数。

SmartPointer ( const SmartPointer& obj ){    sp = obj.sp;    const_cast
(obj).sp = NULL;}

我们实现了拷贝构造函数,因为同一片区域只能有一个指针指向,所以,我们在把obj指向的地址赋给sp后,要将obj的sp赋值为NULL。这里用到了一个强制类型转换。

现在,我们要在类内实现重载赋值操作符。

SmartPointer& operator = ( const SmartPointer& obj ){    if ( this != &obj ){        delete sp;        sp = obj.sp;        obj.sp = NULL;    }    return *this;}

到这里为止,我们就把智能指针类实现完毕了。同时,使用智能指针还可以避免指针比较或加减运算,因为这些运算会造成指针越界带来的bug。好了,我们看一下,运行结果,符不符合我们的预期。

细说智能指针
哇,非常符合。指针使用完毕后完美释放。
下面是完整代码:

#include 
#include
using namespace std;class Girlfriend{private: int pictures;public: Girlfriend ( int i ){ this->pictures = i; cout << "Girlfriend ( int i )" << endl; } int getPic ( void ){ return this->pictures; } ~Girlfriend (){ cout << "~Girlfriend ()" << endl; }};class SmartPointer{private: Girlfriend* sp;public: SmartPointer ( Girlfriend* p = NULL ){ sp = p; cout << "SmartPointer ( Girlfriend* p = NULL )" << endl; } Girlfriend* operator -> (){ return sp; } Girlfriend& operator * (){ return *sp; } SmartPointer ( const SmartPointer& obj ){ sp = obj.sp; const_cast
(obj).sp = NULL; } SmartPointer& operator = ( const SmartPointer& obj ){ if ( this != &obj ){ delete sp; sp = obj.sp; const_cast
(obj).sp = NULL; } return *this; } bool isnull (){ return ( sp == NULL ); } ~SmartPointer (){ cout << "~SmartPointer()" << endl; delete sp; }};int main ( int argc, char** argv ){ SmartPointer Alice = new Girlfriend( 100 ); SmartPointer Lisa = new Girlfriend( 200 ); cout << "my girlfriend Alice's pictures are " << Alice->getPic() << endl; cout << "my girlfriend Lisa's pictures are " << Lisa->getPic() << endl; system ( "pause" ); return 0;}

后记:

这篇文章写完也是花了我两个小时了,这其中的代码都是经过我自己电脑测试的。虽然写这篇文章只花了我两个小时,但是,我在写这篇文章之前就已经开始在构思了,该如何写,才能做到通俗易懂。看来真的,想写好一篇文章还是比较困难的,毕竟要把自己学会的东西,通过语言文字描述出来,还是不容易的。之前写的一篇《细说C++的友元》上了博客的推荐,这里非常感谢51cto的小编。因为,那篇文章的缘故,我尽心尽力的写了这篇文章。
希望看完的小伙伴能够学到些知识,如果觉得我哪里讲解的有误,也可以在评论中指出,或者哪里有不懂的地方,也可以在评论中留言,如果有空,我们可以探讨下。
同时,感谢51cto的小伙伴们,大佬们花时间耐着性子看完了这篇文章,谢谢,谢谢你们!
最后,当然是希望,看完的小伙伴们,有所收获后点个赞,表示支持。谢谢!

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------欢迎打赏!哈哈哈哈!

细说智能指针

细说智能指针

细说智能指针
细说智能指针
细说智能指针
这些教程都挺好的,感兴趣的大佬可以用我的二维码购买!

转载于:https://blog.51cto.com/chen0547/2060896

你可能感兴趣的文章
week5
查看>>
Unity3D常用网络框架与实战解析 学习
查看>>
继承(原型链继承)
查看>>
如何利用 Visual Studio 自定义项目或工程模板(转载)
查看>>
java.lang.Object底层代码分析-jdk1.8
查看>>
获取函数所在模块的方法
查看>>
QtTableView
查看>>
Android应用开发基础--Adapter
查看>>
条件随机场
查看>>
别人要访问我的电脑上部署的tomcat,必须关闭防火墙吗?
查看>>
作业六
查看>>
c++ 二叉树打印节点路径
查看>>
ios--编码规范
查看>>
JsCV Core v0.2发布 & Javascript图像处理系列目录
查看>>
MVC中实现部分内容异步加载
查看>>
PTA编程总结2:
查看>>
剑指OFFER——顺时针打印矩阵
查看>>
Live Archive 3490 - Generator 概率
查看>>
Oracle SQL Developer
查看>>
Java 线程池框架核心代码分析
查看>>