使用C++做算法时,对内存的管理的办法
使用C++做算法时,对内存的管理的办法
最近老是在想C++的内存控制机制,查了一些资料所以有点想法,自己记录一下免得以后自己忘了。
1. 需求
在做线性代数的算法时,首要的就实现Matrix这个类。由于Matrix的行列可变化,所以必须使用动态的内存分配。动态的内存分配就必须要考虑内存的申请和释放,以及动态内存在不同对象之间的传递机制。考虑到算法的复杂性,所以在Matrix之外不打算使用指针,以降低算法实现的复杂度。
2. 可实现的方法
总体上,我能找到的方法有以下2种。
- 利用默认的构造复制构造函数和默认重载以及赋值操作函数动态申请和释放内存和引用计数机制实现不同对象之间对同一块内存的共享,最后只有一个对象负责将动态申请的内存块释放掉,例如OpenCV中的Mat等类使用的就是这种技术。
- 利用C++的复制构造函数和重载赋值操作,将对象的复制构造和赋值统统进行深度复制,这样每个对象负责一个动态申请的内存块,互不干扰。例如STL的vector等容器。
感谢C++11引入的分享指针和右值引用,所以还有两种新的办法。
3. 使用分享指针。分享指针将负责动态申请的内存的释放,利用C++的默认复制构造函数和默认重载赋值操作即可。由于分享指针不能动态申请内存块,所以 以动态申请vector<T>代替。该方法与上述方法1相似,只是利用分享指针控制内存。
4. 利用C++的右值引用,实现移动语义。重载C++类的复制构造函数和重载赋值操作,实现对动态数据的深度复制,利用移动构造函数和移动赋值操作实现对 动态数据的管理权的获取。
3. 方法的比较
- 第一种方法算是一种使用比较流行的办法。好处自然就不必说了,不同对象之间可以共享动态内存,在数据量大的时候避免重复移动数据造成开销,程序的效率高。但是,其优点也是其缺点,在数学计算和赋值中,必须时刻警惕,到底哪些对象共享了内存,或者现在对象的内存是谁申请的等问题,反而让算法编写充满了紧张气氛。为了安心,还得显示的实现深度赋值操作,在数据之间赋值时显示的调用,让程序看起来不那么的美观。
- 第二种方法是一种很安全,也是C++03中提倡的方法。该方法将动态申请的数据进行深度复制,每个对象一份,互不干扰,跟操作基本数据类型一样。当然,在函数调用中可以采用左值引用方法,同样也具备效率优势。但是,在一些临时数据出现的地方,这种方法就需要进行没必要的深度复制,浪费计算资源,例如函数返回临时对象。同样,如果数据量大,该方法将大量的使用堆中数据,这时,不得不使用指针来缓解,而这又增加了算法编程的复杂度。
- 第三种方法与第一种方法类似,只是实现方法不一样,不再赘述。
- 第四种方法是C++11提倡的方法,总体来说,实在第二种方法基础之上增加了移动语义,将利用临时变量的地方可以实现动态数据管理权的转让,这样不必进行深度的数据复制,提高程序的运行效率。该方法需要理解新引入的右值引用(以前的引用称为左值引用),编译器遇到右值将调用移动构造函数或者移动赋值操作。同样,也可以强制语义移动,如果非得进行移动的话,例如临时对象作为返回值。该方法基本上缓解了动态内存管理和数据安全效率之间的矛盾。但是,对象之间的数据是不分享的,如果想让对象之间分享数据,该方法不支持。
4. 总结
如果是用于线性代数计算,而且不适用指针的话,我会采用第四种方法和引用来编写算法。只是,目前支持C++11的编译器不多,如Visual 2012和Gnu g++4.8,因此,写出来的程序只能使用原来的代码用在较新的编译器里,而不能使用在不支持C++11编译器里。
使用C++做算法时,对内存的管理的办法的更多相关文章
- MS SQL SERVER执行大脚本文件时,提示“内存不足”的解决办法
问题描述: 当客户服务器不允许直接备份时,往往通过导出数据库脚本的方式来部署-还原数据库, 但是当数据库导出脚本很大,用Microsoft SQL Server Management Studio执行 ...
- 初学vue 在做项目时遇到的问题与解决办法(使用element组件)(二)
表格每行里都有按钮 <el-table-column prop="option" label="操作" align="center" ...
- 亿级数据时,内存性能低于IO性能
最近因项目需要,需要生成有0到99999999共1亿的不重复数,于是想着直接将这些数据生成为一个文件就可以了,代码如. private void generate(string savePath) { ...
- 复习做UWP时涉及到的几种加密签名相关
本人菜鸟一枚,大学里凭兴趣学了一点WP的皮毛,后来又幸运(或者不幸)的进了一家专注于Windows生态的公司做了一段时间的UWP.在博客园写点自己遇到的东西,作为分享,也作为自己的备忘,如果有错误的地 ...
- 关于Class对象、类加载机制、虚拟机运行时的内存布局的全面解析和推测
简介: 本文是对Java的类加载机制,Class对象,反射原理等相关概念的理解.验证和Java虚拟机中内存布局的一些推测.本文重点讲述了如何理解Class对象以及Class对象的作用. 欢迎探讨,如有 ...
- Java运行时环境---内存划分
背景:听说Java运行时环境的内存划分是挺进BAT的必经之路. 内存划分: Java程序内存的划分是交由JVM执行的,而不像C语言那样需要程序员自己买单(C语言需要程序员为每一个new操作去配对del ...
- [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义
前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine ,既然是虚拟机, ...
- 了解JVM运行时的内存分配
了解JVM运行时的内存分配 前言 上文中,在介绍运行时数据区域中的 JAVA 堆时,提到了 JVM 中的堆,一般分为三大部分:新生代.老年代.永久代,本文将进一步了解运行时的内存分配情况. 正文 1. ...
- objective-c启用ARC时的内存管理 (循环引用)
PDF版下载:http://download.csdn.net/detail/cuibo1123/7443125 在Objective-C中,内存的引用计数一直是一个让人比较头疼的问 ...
随机推荐
- Swift中文教程(五)--对象和类
原文:Swift中文教程(五)--对象和类 Class 类 在Swift中可以用class关键字后跟类名创建一个类.在类里,一个属性的声明写法同一个常量或变量的声明写法一样,除非这个属性是在类的上下文 ...
- C++学习笔记32 断言函数
首先,让我们来看看百度百科上"断言函数"定义说明: 1定义fr=aladdin#" class="nslog:1019" title="编辑 ...
- Linux内核源代码情景分析-中断半
一.中断初始化 1.中断向量表IDT初始化 void __init init_IRQ(void) { int i; #ifndef CONFIG_X86_VISWS_APIC init_ISA_irq ...
- 10个实用的PHP正则表达式汇总
原文 10个实用的PHP正则表达式汇总 正则表达式是程序开发中一个重要的元素,它提供用来描述或匹配文本的字符串,如特定的字符.词或算式等.但在某些情况下,用正则表达式去验证一个字符串比较复杂和费时.本 ...
- 新手sqlserver数据库dba需要注意的小细节
前言:任何的优化和修改都是以业务情况为前提,可能有的写的有误或者不准确的地方,欢迎各位来拍砖. 1.在创建db的时候自增长建议设置成按MB(M)增长,步长根据业务量来设置,一般情况建议设置100-20 ...
- DELL iDRAC 远程虚拟机报错:虚拟介质分离或所选虚拟磁盘驱动器的虚拟介质重定向已由另一用户使用
原因很简单,那就是虚拟介质的映射功能,只能被使用一次. 推荐做法: 1.由于通过远程,在Lifecycle Controller里DeployOS安装系统,需要在虚拟介质里映射ISO,因此映射功能要留 ...
- Web开发的发展
领导以前是做C的,没有做过Web开发,就问我,Web技术发展的大致过程,我就是简单的说了开发过程的演化,下来后有自己找些资料补充下,如下所示:(着这是个简单的说明,感兴趣的可以再自己找找资料). 1. ...
- 1.1 什么是LinQ
如今,软件应用环境越来越多样化,软件需要处理的数据量也日渐庞大,数据之间的关系日渐复杂.从而带动了存储技术的不断发展,越来越多的数据存储格式被应用到各种软件中. 通常,针对数据的查询是用简单的字符串文 ...
- javascript 正则介绍
1.正则直接量字符 \o NUL字符(\u000)\t 制表符\n 换行符(\u000A)\v 垂直制表符\f 换页符\xnn 由16进制nn指定的拉丁字符\uXXXX 由16进制XXXX指定的unc ...
- sql语句 面试题
ql语句 面试题 自动编号 学号 姓名 课程编号 课程名称 分数 1 2005001 张三 0001 数学 69 2 2005002 李四 ...