当前位置: 首页 > 编程日记 > 正文

智能指针1.0

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

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

比如下面的程序

情况一:

#include<iostream>

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 T>

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<iostream>

using namespace std;

struct A

{

inta;

intb;

};

template<class T>

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<T>&p)

:_ptr(p._ptr)

,_owner(p._owner)

{

p._owner= false;

}

AutoPtroperator=(AutoPtr<T>& 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()

{

AutoPtr<int>p(new int);

*p= 10;

cout<< *p << endl;

AutoPtr<int>p2(p);

*p2= 20;

cout<< *p2 << endl;

AutoPtr<A>pa(new A);

AutoPtr<int>p3;

p3= p2;

*p3= 30;

cout<< *p3;

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

}

auto_ptr问题分析

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

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

scoped_ptr

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

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

#include<iostream>

using namespace std;

template<class T>

class ScopedPtr

{

public:

ScopedPtr(T*ptr = NULL)

:_ptr(ptr)

{}

~ScopedPtr()

{

delete_ptr;

}

private:

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

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

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

private:

T*_ptr;

};

void ScopedPtrTest()

{

ScopedPtr<int>p(new int);

ScopedPtr<int>p1(p);

}

相关文章:

gen_event中的handler和supervised handler

呃&#xff0c;在gen_event中有两个添加handler的方法 gen_event:add_handler/3 gen_event:add_sup_handler/3 一开始总是有些迷惑两者的区别&#xff0c;今天查看了gen_event源码&#xff0c;总算弄清两者的区别。 add_handler添加的只是把gen_event作为容器&#xff0c;仅仅在…

动态刷新_屋盖“起飞”刷新国内记录,中建八局杭州萧山国际机场项目最新动态来袭...

近日&#xff0c;中建八局承建的杭州萧山国际机场三期项目完成了一件“壮举”T4航站楼首段钢屋盖网架顺利提升至设计标高一举刷新了国内机场航站屋盖单次提升的记录正式进入主楼屋面及幕墙施工的新篇章两段视频速看首段钢屋架提升刷新记录 覆盖测量全过程监控杭州萧山国际机场…

逻辑 STANDBY ORA-00368日志应用失败处理一例

故障现象&#xff1a;逻辑STANDBY数据库注册日志成功&#xff0c;但应用日志出现错误&#xff0c;提示“ORA-00368: checksum error in redo log block”&#xff0c;显然是文件受到了破坏。Tue Jul 24 08:25:59 2012LOGMINER: WARNING: error 368 encountered, failed to read…

Linux 下实现虚拟光驱功能,查看iso文件内容

1,创建挂载点&#xff08;也可以不创建&#xff0c;直接用现有的目录&#xff09;openSUSE:~ # mkdir /mnt/iso2&#xff0c;挂载ISO文件至创建的挂载点openSUSE:~ # mount -t iso9660 -o loop /home/ubuntu-14.04.5-server-amd64.iso /mnt/isomount参数解释&#xff1a;-t&…

clientcontainerThrift Types

首先声明&#xff0c;我是一个菜鸟。一下文章中出现技术误导情况盖不负责 来自Apache Thrift官网&#xff1a;Thrift Types Thrift Types The Thrift type system is intended to allow programmers to use native types as much as possible, no matter what programming lang…

简易git操作 -- 让你的格子绿起来

创建github账号 浏览器输入网址&#xff0c;申请一个github账号&#xff0c;github申请网址&#xff0c;看到下面的图片内容&#xff0c;点击图中红色框里面的内容&#xff0c;用邮箱账号申请一个github账号&#xff0c;一定记住账号和密码 填写注册信息 点击之后跳转到下面…

c语言自定义char*函数返回值是乱码_[每日C语言」printf()函数的修饰符和返回值...

在上一个小demo《printf()函数(1)》中主要说了一下printf()函数的转换说明符&#xff0c;这些转移说明符是可以被修饰的。我们可以在%d和定义的转义字符之间通过插入修饰符对基本的转换说明加以修改。printf()修饰符digit(s) 字符宽度的最小值结果&#xff1a;不够的前面补空格…

win2003辅助域服务器相关几个错误日志的解决办法

1.域助域上做了DNS后,提示:浏览器无法更新服务状态位,数据有错误,错误代码是8007关闭computer browser基本就行了,有人说还要关server,它负责共享之类的,如果关了,就不能共享了,我个人没有关!2.之前,公司主域上有DNS,不过没有允许复制区域,也没有在辅助域上做DNS,所以在辅助域上…

redis.conf配置文件参数说明

参数说明 redis.conf 配置项说明如下&#xff1a;1. Redis默认不是以守护进程的方式运行&#xff0c;可以通过该配置项修改&#xff0c;使用yes启用守护进程daemonize no2. 当Redis以守护进程方式运行时&#xff0c;Redis默认会把pid写入/var/run/redis.pid文件&#xff0c;可以…

用C#来开发CAD插件,含源代

CAD插件看起来很神秘&#xff0c;其实一个合格码农经过几天就能快速掌握。没什么秘密&#xff0c;开发CAD插件和winform一样简单&#xff0c;多学几个类库用法就是&#xff0c;在CAD里展现界面和winform略有不同。学习CAD插件开发的动机是为了薪水&#xff0c;由于公司是做显示…

动态内存管理和智能指针 2.0 -- shared_ptr

shared_ptr出现原因 通过第一章的学习&#xff0c;我们知道不管是auto_ptr合适scoped_ptr都是存在缺陷的&#xff0c;于是我们必须想出一个方法既能很好的管理我们的内存&#xff0c;而且在使用的时候&#xff0c;可以多个指针指向一个内存&#xff0c;这个时候就出现了shared…

汇总同一时间段的数据_数据集干货:一文读懂Mapsidejoin

我们知道数据分析的第一步是准备数据&#xff0c;所以在前面的课程里&#xff0c;我们介绍了元数据。今天这篇文章&#xff0c;主要介绍大数据量组合数据集在永洪中的应用实例&#xff1a;Mapsidejoin。什么是Mapsidejoin&#xff1f;按照字面意思&#xff0c;Mapsidejoin就是M…

【强烈推荐】国土档案管理信息系统产品使用说明书系列目录【附下载地址】...

<<国土档案管理信息系统>>产品使用说明书系列目录【附下载地址】——通过知识共享树立个人品牌。《国土档案管理信息系统》在线视频讲解一、记大型商业软件<<国土档案管理信息系统>>之系统简介记大型商业软件 > 之系统简介 ——通过知识共享树立个人…

zip函数的使用

s [[1, 10], [1.2, 11], [2, 5], [5, 15]] data zip(*s) x_list data[0] y_list data[1] x_min min(x_list) x_max max(x_list) y_min min(y_list) y_max max(y_list) box [x_min, x_max, y_min, y_max] print(box) # [1, 5, 5, 15] 转载于:https://www.cnblogs.com/…

计算机网络基础 1.0 -- 概述

概念理解 报文&#xff1a;在网络中发送的数据块成为报文在发送报文之前&#xff0c;通常会把数组分组&#xff0c;每个组都有个包头和数据组成&#xff0c;包头中包含了诸如目标地址和源地址等重要信息&#xff0c;这样才保证了数据能够有目的的在网络中的传输主机是用户用来…

字符串循环同构的最小表示法(转)

循环字符串的最小表示法的问题可以这样描述&#xff1a; 对于一个字符串S&#xff0c;求S的循环的同构字符串S’中字典序最小的一个。 由于语言能力有限&#xff0c;还是用实际例子来解释比较容易&#xff1a;设Sbcad&#xff0c;且S’是S的循环同构的串。S’可以是bcad或者cad…

周长相等的正方形面积一定相等_必考单元:三年级下册面积计算公式+知识点+测试卷(附答案),重点内容,收藏练习!...

《面积》公式 知识点面积和面积单位&#xff1a;1.常用的面积单位有&#xff1a;(平方厘米)、(平方分米)、(平方米)。2.理解面积的意义和面积单位的意义。面积&#xff1a;物体表面或封闭图形的大小&#xff0c;叫做它们的面积。1平方米&#xff1a;边长是1米的正方形&#xff…

sql server 2000 版本查询

确定已安装的 SQL Server 2000 Database Components 版本 使用 isql、osql 或查询分析器&#xff0c;对数据库引擎实例执行以下查询之一。 SELECT SERVERPROPERTY(ProductLevel) SELECT VERSION SELECT SERVERPROPERTY(Produc…

ubuntu16创建开机启动服务

1、cd /etc/init.d/ 2、sudo touch zookeeper&#xff08;举例&#xff09; 3、给服务赋权限&#xff1a;sudo chmod x zookeeper 4、执行sudo vim zookeeper 命令写入执行脚本&#xff08;启动脚本中的启动命令对应服务的启动命令&#xff09; #! /bin/sh### BEGIN INIT INFO …

Effective C++ 1.0 -- 概述

声明 对象声明&#xff0c;函数声明&#xff0c;类型声明&#xff0c;是告诉编译器某个东西的 名称和类型&#xff0c;但是略去了实现 细节&#xff0c;因为定义在其他的地方。 external int x; //对象&#xff08;object&#xff09;声明 std:size_t numDigits(int num…

寻找连通域算法_【车牌识别算法】

车牌识别技术要求能够将运动中的汽车牌照从复杂背景中提取并识别出来&#xff0c;通过车牌提取、图像预处理、特征提取、车牌字符识别等技术&#xff0c;识别车辆牌号、颜色等信息。目前车牌识别技术主要分为端到端识别与车牌分割识别两种识别算法。端对端识别技术端到端车牌识…

SQL 2005 删除带有默认值约束的列

在sqlserver 2005中要删除某一列: alter table [表名] drop column [列名] 但是如果该列被创建了默认值约束&#xff0c;我们就只能先删除默认值约束&#xff0c;然后才能删除该列。 第一种方法&#xff1a; 1、删除默认值约束: DECLARE name varchar(100) SELECT nameb.name F…

apple hosts

2019独角兽企业重金招聘Python工程师标准>>> #Apple #125.56.202.7 swcnd.apple.com 203.69.138.34 a1.phobos.apple.com 203.69.138.34 a2.phobos.apple.com 203.69.138.34 a3.phobos.apple.com 203.69.138.34 a4.phobos.apple.com 203.69.138.34 a5.phobos.apple.…

thymeleaf 的常见属性

转载于:https://www.cnblogs.com/hwgok/p/9637723.html

继承和多态 1.0 -- 继承概念(is-a、has-a,赋值兼容规则,隐藏重定义)

普通继承和访问权限 当一个继承没有虚拟继承或者是多重继承时&#xff0c;就是一个简单的继承的时候&#xff0c;这个时候就是一个普通的继承。 普通继承的内存空间是&#xff1a;子类的对象中&#xff0c;包含了父类的成员变量&#xff0c;同时也可以调用父类的成员函数&…

c++标准库 及 命名空间std

1、命名空间std  C标准中引入命名空间的概念&#xff0c;是为了解决不同模块或者函数库中相同标识符冲突的问题。有了命名空间的概念&#xff0c;标识符就被限制在特定的范围(函数)内&#xff0c;不会引起命名冲突。最典型的例子就是std命名空间&#xff0c;C标准库中所有标识…

aop point 只能获取到map嘛_面试被问了几百遍的 IoC 和 AOP ,还在傻傻搞不清楚?...

这篇文章会从下面从以下几个问题展开对 IoC & AOP 的解释什么是 IoC&#xff1f;IoC 解决了什么问题&#xff1f;IoC 和 DI 的区别&#xff1f;什么是 AOP&#xff1f;AOP 解决了什么问题&#xff1f;AOP 为什么叫做切面编程&#xff1f;首先声明&#xff1a;IoC & AOP…

HTML学习笔记_002_如何学习HTML

.htm 还是 .html 文件后缀&#xff1f; 当您保存 HTML 文件时&#xff0c;既可以使用 .htm 也可以使用 .html 文件后缀。我们在实例中使用 .htm。这只是长久以来形成的习惯而已&#xff0c;因为过去的很多软件只允许三个字母的文件后缀。 不过对于新的软件&#xff0c;使用 .ht…

设计1.0 -- iterator 和const_iterator底层的模拟实现

本文概要&#xff1a; 本文主要是模拟实现STL中迭代器和const迭代器的&#xff0c;主要阐述的一个问题就是&#xff0c;为什么我们在设计迭代器的时候需要使用三个模板参数呢 在设计迭代器的时候&#xff0c;我们有下面的代码 #include<iostream> using namespace std…

关于python缩进的描述中_关于Python程序中与“缩进”有关的说法中,以下选项中正确的是()...

关于Python程序中与“缩进”有关的说法中,以下选项中正确的是()答&#xff1a;缩进在程序中长度统一且强制使用同文学或同音乐主题的民歌&#xff0c;《_______》是其中之一。此曲经民间艺人丁喜才改编后&#xff0c;由上海音乐学院鞠秀芳于50年代在国际上唱红答&#xff1a;五…