C++的复杂是一个基本事实,这也成了很多人对C++横加指责的原因。事实上,正如陈皓在“C++的数组不支持多态”?这篇文章中提到的,很多人在并不真正了解C++的情况下,就喜欢得出这样的结论。更有甚者,把C语言本身的“坑”也归结为C++的问题。这样的人着实不少,C++11作为最具争议的语言之一,每一次讨论到涉及语言选择的时候,都会引起一场“血战”,但结果往往不了了之,喜欢C++的继续坚守C++阵营,讨厌C++的把精力留到下次黑C++的时候。对于客观公正批评C++的,我内心尊敬佩服;而对于还没搞清楚C++就信口开河的,我表示鄙视。任何一门语言都有自己的历史背景和定位,C++被设计成这样,从历史上来看,是为了兼容C,使得C程序可以不用修改就可以继续使用;从定位上看,就是三大约束:与C的完全兼容、静态类型检查、最高性能。我真心的希望,如果有人不喜欢C++,在搞懂它之后再黑,免得误人子弟。

每次写C++的优点之前,都想好好发泄一下,好了,言归正传。这篇文章想探讨下C++中的资源管理,谈到资源管理,就不得不谈异常安全,正是因为有了异常,才使得资源管理变得更加重要。C++11提供了一套非常好的编程Idom来处理这个问题,C++11的新特性使得这些Idom变得更加易用。

计算中的资源是个非常广泛的概念,内存、锁、文件、Socket等等都是资源,C++中可以通过统一的方式管理这些资源,即RAII(参见The C++ Programming Lauguage, Special Edition, p364, 14.4节)。其基本思路非常简单,用类来封装资源,在类的构造函数中获取资源,在类的析构函数中释放资源。使用的时候,把这个类在栈上面实例化出一个对象,当这个对象超出作用域时,这个对象的析构函数会被调用,从而释放资源。正是这个简单的方式,构成了C++资源管理的基础,并且这样的方式是异常安全的,因为:1、如果在对象构造之前发生异常,则资源还没申请,不会有问题;2、如果在类的构造函数中发生异常,C++编译器保证资源不会发生资源泄漏(参见Exceptional C++, p26, Item8);3、在对象构造好之后发生了异常,stack unwinding(参见The C++ Programming Lauguage, Special Edition, p355, 14.1节)的过程中,C++标准要求编译器保证当前栈上面成功构造的对象的析构函数一定会得到调用,内存一定得到释放。

智能指针就是RAII的实现范例,专门用来管理内存,C++11中有三个智能指针:unique_ptr、shared_ptr和weak_ptr。auto_ptr已经是过时的了,它的功能被unique_ptr取代了,后者可以用于STL容器。

对于其它资源,需要用户自己去封装,同样的资源只要封装一次,以后使用起来就方便了。如果嫌每个资源都要用类包装起来麻烦,可以利用ScopeGuard来处理,这个设施由Andrei Alexandrescu发明,刘未鹏在C++11(及现代C++风格)和快速迭代式开发中做了详细介绍。当然了,ScopeGuard在C++11(得益于std::function和lambda表达式)下,才达到了非常易用的地步。我这边贴一下SocpeGuard的代码,有兴趣的可以参考刘未鹏的文章。

class ScopeGuard
{
public:explicit ScopeGuard(std::function<void()> onExitScope): onExitScope_(onExitScope), dismissed_(false){ }~ScopeGuard(){if(!dismissed_){onExitScope_();}}void Dismiss(){dismissed_ = true;}private:std::function<void()> onExitScope_;bool dismissed_;private: // noncopyableScopeGuard(ScopeGuard const&);ScopeGuard& operator=(ScopeGuard const&);
};

使用起来很简单,在以C的方式申请一个资源的时候:

HANDLE h = CreateFile(...);
ScopeGuard onExit([&] { CloseHandle(h); });

这样申请资源和释放资源永远写在一起,不会忘记,而且保证资源永远不会泄漏。

说到资源泄漏,当然想到内存泄漏了,Visual C++中可以这样的方式来检测内存泄漏:

在cpp文件开始处,添加这么一段代码:

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif // _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif // _DEBUG

在某个函数中,添加这么一个函数调用:

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);

这样一来,在程序在Debug模式运行结束后,如果有内存泄漏的话,会打印出类似如下的检测信息。

Detected memory leaks!
Dumping objects ->
{197} normal block at 0x00FBCE98, 44 bytes long.Data: <                > 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Object dump complete.

谈了C++资源管理的好处,来吐槽下Java。Java是个喜欢喊口号的语言,“一次编译,到处运行(Write once,run anywhere) ”,“程序员再也不用担心内存泄漏了”,“纯粹的面向对象语言”,诸如此类。其它先不说,就谈谈它的资源管理。Java中对资源的管理分为两种,一是内存,通过gc管理;二是其它资源,通过try、catch和finally来管理。第一个问题,不统一,Java里面不统一的地方还有很多,比如基础数据类型不能作为模板参数、明明是“纯粹的面向对象语言”却还有基本数据类型等等。第二个问题,try、catch和finally语法太丑了,而且最不爽的是在finally里面还要在try一下,太蛋疼了!第三个问题,内存被JVM管理了,导致gc时机不确定,严重影响Java的普及范围(在一个大型游戏中,正打boss呢,突然gc了,然后,然后就没有然后了)。我承认,Java是个很好用的语言,能很大程度提高程序员的开发效率,特别是JavaEE体系,的确很成熟。我自己也写过不少Java代码,最方便的地方是出错了以后,异常栈能够快速帮助我定位到bug。但是Java因为屏蔽了太多底层信息,导致它培养了一大批不太合格的程序员。这里不是说Java程序员不优秀,只是如果一直用Java,不去了解C/C++的话,真的很容易退化。

转载于:https://www.cnblogs.com/codemood/archive/2013/05/05/3060740.html

浅谈C++中的资源管理相关推荐

  1. java 中的单元测试_浅谈Java 中的单元测试

    单元测试编写 Junit 单元测试框架 对于Java语言而言,其单元测试框架,有Junit和TestNG这两种, 下面是一个典型的JUnit测试类的结构 package com.example.dem ...

  2. mybatis与php,浅谈mybatis中的#和$的区别

    浅谈mybatis中的#和$的区别 发布于 2016-07-30 11:14:47 | 236 次阅读 | 评论: 0 | 来源: 网友投递 MyBatis 基于Java的持久层框架MyBatis 本 ...

  3. 浅谈CSS3中display属性的Flex布局,关于登陆页面属性框的设置

    声明:本文转发自三里屯柯南的浅谈CSS3中display属性的Flex布局http://www.cnblogs.com/xuyuntao/articles/6391728.html 基本概念 采用Fl ...

  4. python sys模块作用_浅谈Python中的模块

    模块 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式.在Python中,一个.py文件就称之为一个模块(Mod ...

  5. python生成器和迭代器作用_浅谈Python中的生成器和迭代器

    迭代器 迭代器协议 对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么返回一个异常来终止本次迭代.(只能往前走,不能往后退!) 迭代器对象 遵循了(实现了)迭代器协议的对象.(对象内 ...

  6. oracle hash join outer,CSS_浅谈Oracle中的三种Join方法,基本概念 Nested loop join: Outer - phpStudy...

    浅谈Oracle中的三种Join方法 基本概念 Nested loop join: Outer table中的每一行与inner table中的相应记录join,类似一个嵌套的循环. Sort mer ...

  7. 浅谈caffe中train_val.prototxt和deploy.prototxt文件的区别

    浅谈caffe中train_val.prototxt和deploy.prototxt文件的区别 标签: caffe深度学习CaffeNet 2016-11-02 16:10 1203人阅读 评论(1) ...

  8. python中 是什么类型_浅谈python中的变量默认是什么类型

    浅谈python中的变量默认是什么类型 1.type(变量名),输出的结果就是变量的类型: 例如 >>> type(6) 2.在Python里面变量在声明时,不需要指定变量的类型,变 ...

  9. 浅谈Java中的Set、List、Map的区别

    就学习经验,浅谈Java中的Set,List,Map的区别,对JAVA的集合的理解是想对于数组: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),JAVA集合可以存储和操 ...

最新文章

  1. js正则验证特殊字符
  2. 模块化数据中心成未来互联网企业首选
  3. HTML页面背景音乐控制
  4. spring学习(15):required属性
  5. 精通ASP.NET MVC ——控制器可扩展性
  6. 第二场周赛(递归递推个人Rank赛)——题解
  7. java textarea 自动滚动条_月光软件站 - 编程文档 - Java - 如何实现滚动条的自动滚动到textarea的末尾...
  8. C专家编程(学习笔记)_第10章 再论指针
  9. python网络爬虫实践_《python 网络爬虫从入门到实践》笔记
  10. 基于ROS使用Arduino控制水泵
  11. docx文档怎么排列图片_怎么把图片文字转换成word文档
  12. Mac OS X中virtualenv里python shell无法使用光标键问题的解决
  13. SilkTest武林外史之7-简单web测试
  14. PGO 是啥,咋就让 Go 更快更猛了?
  15. 王者荣耀转系统服务器繁忙,换手机党的福音,王者荣耀开启跨系统角色转移,但这些问题要注意...
  16. java写一个文件浏览器_【Java】 实现一个简单文件浏览器(2)
  17. 使用git对word进行版本控制
  18. C#算法:推算经理的3个女儿的年龄
  19. 综述 | 激光与视觉融合SLAM
  20. 如何不使用快压解压快压超高压缩比压缩的文件?

热门文章

  1. mysql sbr_腾讯云数据库团队:MySQL语句复制(SBR)的缺陷列举
  2. 实体-关系信息抽取上线使用F1值87.1% (附数据集)
  3. 如何构建数据指标体系?
  4. redis迁移至linux,redis几种数据导出导入方式
  5. 与roc的区别_2020斯柯达柯珞克Karoq对比大众T-ROC,你会选哪个?
  6. 计算机三级上机考试题库,计算机三级数据库上机试题及答案
  7. 隔行变色java代码_纯js实现隔行变色效果
  8. python text insert()背景色_50行python代码写个计算器教程
  9. 浅层分析-shallow parsing
  10. JBoss + EJB3 + MySql : 开发第一个EJB