首页 > 智能指针1.0

智能指针1.0

一.使用普通的动态内存开辟存在的问题

我们在使用动态内存开辟一个空间的时候,需要释放掉这个空间,不然就容易出现内存泄漏。

比如下面的程序

情况一:

#include

using namespace std;

int errorTest()

{

         intflag = 0;

         cin>> flag;

         int*p = new int;

         if(flag)

         {

                   cout<< "success" << endl;

                   return0;

         }

         else

         {

                   deletep;

                   cout<< "error" << endl;

                   return1;

         }

}

如果我们的程序是正确的条件,那么这个时候直接是返回的,此时一种情况就是我们动态开辟的空间没有释放掉

情况二:

void errorTest2()

{

         int*p;

         try

         {

                   p= (int*)malloc(1000);

         }

         catch(...)   //如果捕获到了一个异常,程序就会跳转了,然后就没有下面的delete了

         {

                   throw;

         }

         deletep;

}

如果我们捕获了一个异常,那么这个时候我们的程序就直接跳转了,下面的代码是不执行的,这个时候我们的资源也没有释放掉

 

有的同学可能就会说了,这里我开辟的资源少,对我的系统影响很少的,还有的同学可能也会给出另外的一种解释就是,我们开辟的资源是在堆上面开辟的,当我们的进程退出之后,我们的资源就释放了,但是如果是这样的一种情况呢,我们的服务器是7*24小时一直运行着的,而且我们的这一段代码可能还是循环执行着的,这样一点点占据资源,我们的内存迟早有点会被吃完,然后我们的服务器就崩溃掉了。

二.解决办法

我们想到C++类中有一些函数是自动的调用的,就是构造函数和析构函数,我们想利用这个来进行动态内存的管理,就是让一个动态空间在使用结束后就直接释放掉了。

这里首先想到的就是一个定义一个类,用这个类实例化的对象来维护我们的动态空间。

这里我们要用到一种技术是RAII技术,就是资源获得即初始化

管理权的转移

auto_ptr

这里首先提出的一个方法是auto_ptr,下面我们就来模拟实现这个类

先看一个简单的代码

template

class AutoPtr

{

public:

         AutoPtr(T*ptr)

                   :_ptr(ptr)

         {}

         ~AutoPtr()

         {

                   delete_ptr;

         }

         //这里应该返回的是一个对象,这里T就是一个对象,然后我们需要改变里面的内容,所以这里返回的应该是T&

         T&operator*()

         {

                   return*_ptr;

         }

         T*operator->()   //这里相当于是放回了一个指针,然后在使用这个指针指向一个内容

         {

                   return_ptr;

         }

private:

         T*_ptr;

};

下面我们还需要实现的一个内容是拷贝构造函数还有赋值运算符的重载

拷贝构造函数的时候就不得不想的一个问题就是,如果我们多个指针维护一个空间的话,当一个指针结束后,释放了,那么当其他的指针结束之后再次释放,程序就会崩溃掉了,因为之前的内容已经释放掉了

我们首先想到的方法是深拷贝,就是每次拷贝的时候都给这个指针开辟一个空间,但是这种设计是不符合我们的使用要求,我们既然要求它像指针一样使用,那么当我们的一个指针使用*p改变空间内容的时候只有当前的内容改变了,但是其他的内容没有改变,所以这种是不符合我们的要求的

这个时候我们想解决的办法就是在设计这个类的时候我们可以多设计一个BOOL型变量,对于动态空间的释放权只能 有一个指针有权限管理,其他的指针没有这个权限,而且我们规定只有最后一次拷贝构造的那个指针有这个权限去释放指针。

按照这个思路我们的拷贝构造函数还有我们的赋值运算符的重载应该设计成下面的形式

#include

using namespace std;

struct A

{

         inta;

         intb;

};

template

class AutoPtr

{

public:

         AutoPtr(T*ptr = NULL)

                   :_ptr(ptr)

                   ,_owner(true)

         {}

         ~AutoPtr()

         {

                   if(_owner == true)

                   delete_ptr;

         }

         //这里应该返回的是一个对象,这里T就是一个对象,然后我们需要改变里面的内容,所以这里返回的应该是T&

         T&operator*()

         {

                   return*_ptr;

         }

         T*operator->()   //这里相当于是放回了一个指针,然后在使用这个指针指向一个内容

         {

                   return_ptr;

         }

         AutoPtr(AutoPtr&p)

                   :_ptr(p._ptr)

                   ,_owner(p._owner)

         {

                   p._owner= false;

         }

         AutoPtroperator=(AutoPtr& p)

         {

                   if(&p == this)

                   {

                            return*this;

                   }

                   else

                   {

                            if(_owner = true)

                            {

                                     delete_ptr;

                            }

                            _ptr = p._ptr;

                            _owner= p._owner;

                            p._owner= false;

                            return*this;

                   }

         }

private:

         T*_ptr;

         bool_owner;

};

void AutoTest()

{

         AutoPtrp(new int);

         *p= 10;

         cout<< *p << endl;

         AutoPtrp2(p);

         *p2= 20;

         cout<< *p2 << endl;

         AutoPtrpa(new A);

         AutoPtrp3;

         p3= p2;

         *p3= 30;

         cout<< *p3;

         pa->a;   //这里实际上是这个样子的pa.operator*()->a;

}

auto_ptr问题分析

管理权转移了,但是我们还存在着另外的一个问题就是,如果在一个if语句中,我们把使用了拷贝构造函数构造一个p3,这个时候管理权在p3中,因为某些原因p3释放了这个空间,但是我们在if的外面还想使用cout<<*p2<

第二种方式当我们使用拷贝构造函数的时候,比如我们使用了p2(p1),这个时候直接使p1 = NULL

scoped_ptr

为了防止我们的程序出现那样的问题,我们的标准模板库又设计了一种简单粗暴的方式就是防拷贝,这个时候就是只能一个指针管理一个存储空间

代码实现如下(其中只实现了拷贝构造函数部分)

#include

using namespace std;

template

class ScopedPtr

{

public:

         ScopedPtr(T*ptr = NULL)

                   :_ptr(ptr)

         {}

         ~ScopedPtr()

         {

                   delete_ptr;

         }

private:

         ScopedPtr(ScopedPtr&p);   //这里采用的是只声明不定义的方式,那么这个如果我们在使用的时候,编译的时候就会出错

         //这里我们还应该注意的一点就是,我们的拷贝构造函数要放置在private中,如果放置在公有中,这个时候是很有可能被攻击

         //如果被攻击了,然后别人写了一个函数,对我们的程序不力,这个时候就容易造成麻烦

 

private:

         T*_ptr;

};

 

void ScopedPtrTest()

{

         ScopedPtrp(new int);

         ScopedPtrp1(p);

        

        

}

 

更多相关:

  • 英语的重要性,毋庸置疑!尤其对广大职场人士,掌握英语意味着就多了一项竞争的技能。那,对于我们成人来说,时间是最宝贵的。如何短时间内在英语方面有所突破,这是我们最关心的事情。英语学习,到底有没有捷径可以走,是否可以速成?周老师在这里明确告诉大家,英语学习,没有绝对的捷径走,但是可以少走弯路。十多年的教学经验告诉我们,成功的学习方法可以借...

  • 展开全部 其实IDLE提供了一个显32313133353236313431303231363533e78988e69d8331333365663438示所有行和所有字符的功能。 我们打开IDLE shell或者IDLE编辑器,可以看到左下角有个Ln和Col,事实上,Ln是当前光标所在行,Col是当前光标所在列。 我们如果想得到文件代码...

  • 前言[1]从 Main 方法说起[2]走进 Tomcat 内部[3]总结[4]《Java 2019 超神之路》《Dubbo 实现原理与源码解析 —— 精品合集》《Spring 实现原理与源码解析 —— 精品合集》《MyBatis 实现原理与源码解析 —— 精品合集》《Spring MVC 实现原理与源码解析 —— 精品合集》《Spri...

  • 【本文摘要】【注】本文所述内容为学习Yjango《学习观》相关视频之后的总结,观点归Yjango所有,本文仅作为学习之用。阅读本节,会让你对英语这类运动类知识的学习豁然开朗,你会知道英语学习方面,我们的症结所在。学习英语这类运动类知识,需要把握四个原则第一,不要用主动意识。第二,关注于端对端第三,输入输出符合实际情况第四,通过多个例子...

  • 点云PCL免费知识星球,点云论文速读。文章:RGB-D SLAM with Structural Regularities作者:Yanyan Li , Raza Yunus , Nikolas Brasch , Nassir Navab and Federico Tombari编译:点云PCL代码:https://github.co...

  • 原文出处: 韩昊    1 2 3 4 5 6 7 8 9 10 作 者:韩 昊 知 乎:Heinrich 微 博:@花生油工人 知乎专栏:与时间无关的故事   谨以此文献给大连海事大学的吴楠老师,柳晓鸣老师,王新年老师以及张晶泊老师。   转载的同学请保留上面这句话,谢谢。如果还能保留文章来源就更感激不尽了。 我保证这篇文章...

  • 原文出处: 韩昊   我保证这篇文章和你以前看过的所有文章都不同,这是 2012 年还在果壳的时候写的,但是当时没有来得及写完就出国了……于是拖了两年,嗯,我是拖延症患者…… 这篇文章的核心思想就是: 要让读者在不看任何数学公式的情况下理解傅里叶分析。 傅里叶分析不仅仅是一个数学工具,更是一种可以彻底颠覆一个人以前世界观的思维...

  • 很多Linux高手都喜欢使用screen命令,screen命令可以使你轻松地使用一个终端控制其他终端。尽管screen本身是一个非常有用的工具,byobu作为screen的增强版本,比screen更加好用而且美观,并且提供有用的信息和快捷的热键。 想象一下这样一个场景:你通过Secure Shell(ssh)链接到一个服务器,并...

  • NarrowbandPrimary Synchronization Signal时域位置每1个SFN存在一个NPSSSFNSubframeSymbol长度每个SFN5最后11个symbol11个symbols频域位置NB-IOT下行带宽固定180kHz,一个PRB,12个子载波。...

  •  [h1]反斜杠只能够阻止一个字符  [h2]位于键盘的左上角,和~公用一个键。...

  • C++11标准中可以为模板定义别名,比如 template using ptr=std::shared_ptr; //这里模板定义ptr为智能指针std::shared_ptr定义的别名 所以实际应用中可以借此来简化代码,比如 #include #include

  • 先说结论,智能指针都是非线程安全的。 多线程调度智能指针 这里案例使用的是shared_ptr,其他的unique_ptr或者weak_ptr的结果都是类似的,如下多线程调度代码: #include #include #include #include #i...

  • 文章目录unique_ptr 智能指针的实现shared_ptr 智能指针的实现指针类型转换 unique_ptr 智能指针的实现 一个对象只能被单个unique_ptr 所拥有。 #include using namespace std;/*增加模板类型,保证智能指针的类型是由传入的类型决定的*/ t...

  • 文章目录weak_ptr描述声明作用原理实现函数成员使用总结 weak_ptr描述 声明 头文件: 模版类:template class weak_ptr 声明方式:std::weak_ptr statement 作用 根据boost库的官方描述,weak_ptr是...

  • 文章目录shared_ptr描述声明作用原理实现函数使用关于shared_ptr循环引用问题 shared_ptr描述 声明 shared_ptr属于C++11特性中新加的一种智能指针,它的实现方式是模版类,头文件 template class shared_ptr 所以使用shared...