明明白白c++ effective c++ 条目6-10

废话少说,直接开题。

effective c++的下载地址http://download.csdn.net/detail/mlkiller/5335383

条款6:析构函数里对指针成员调用delete

我在想类设计的本身就是,自身是一套完整独立的系统,封装的作用。不同于之前c语言的函数,函数就是一个简单的个体,有点类似于功能机,打电话就是打电话,发短信就是发短信。而类的有点像智能机,它自身很完善,高内聚,低耦合的方式,定义一个类可以完成一系列功能,而不是单单的一种,而且各个类之间有时候还可以通信,就像智能手机里面的app可以直接调用打电话的程序一样。貌似非智能机还没有这个功能。

但是既然它提供了这些功能,自然要付出代价,就是你自己要维护好你的模块。

我这里举个例子,说明类的好处,如果你学习过opencv,你会发现网上很多opencv1.0的例子,而其中50%的代码是在内存分配和内存释放上面做文章,要管理好内存。
但是opencv2.0已经使用了类这个概念,内存的分配和释放就要省心很多了,你可以把大量的精力放到功能的实现上面。

前提,这里的指针是指整个过程中可能会有new分配内存的那些指针。

对于一般情况,正如书上写的:
1 在构造函数中一定要对指针进行初始化。如果开始的时候没有分配空间一定要将指针初始化为NULL
   (这里我有血的教训,有个指针没有初始化,但是在大多数情况下,都分配了内存,有少数情况下没有分配内存,所以有时候出错,有时候正常,查找问题太浪费时间。吃一堑长一智,文档审核代码申请还是十分重要的。)
2 其他功能函数中,先删除内存,再分配内存。(这里决定了要初始化指针为NULL)
3 析构函数,删除指针(删除NULL指针,等于什么都不操作)
     ps:一般情况下,如果删除指针,指针如果不再使用要赋值为NULL,析构函数里面因为是delete或者生命期到了采取调用的,所以这些指针不会再被使用,即使是野指针也没有关系。编程之美在于代码简洁,如果理解深入,很多时候,代码可以很简单。

条款7:预先准备好内存不够的情况

这个条款,其实对于初学者,或者很多小程序来说,或者运行时间比较短的程序来说,并不是特别关心。
一般new分配的空间是在内存上DDR上面的,几个G的空间,可以说是能随便用的,只要你的程序自身内存泄露不是很严重,运行的时间比较短,其实这个问题不是很大。因为程序运行完之后,操作系统帮你回收内存。

但是对于比较大的项目,对于运行时间很长的程序,对于稳定性要求很高的程序,这个十分十分的重要。
你写的一个小bug,在长时间运行之后,很快会消耗光系统的内存,整个程序就会崩溃掉。
我之前写的通信软件中,它们会封装malloc函数,每次分配内存就要检测一下,是不是内存分配出差了。因为内存区域很多核在使用,一旦某个地方由其是TTI调度(可以理解成循环里面)内存分配而不释放,一会系统就会挂掉。

所以,第一,做好内存管理很重要,可以考虑智能指针;第二,如果你的软件要求比较高,还是要自己封装一下new操作符,便于查找问题。

条款8: 写operator new和operator delete时要遵循常规

这几个条款都是关于内存管理方面的,内存是c/c++的核心。很多时候说成也萧何败也萧何,其实也是这个道理,内存管理的好处在于效率,所以很多语言一旦提到自身的效率问题,就会和c++编写的程序进行比较,来展示自己还不错。但是不好的地方呢,这里是 c++最容易出问题的地方之一,内存和指针。很多新人学习c++的时候,很难发现问题所在,debug起来特别困难,一旦出现问题完全没有了思路,内存异常。

这里的条款,我的感触不是那么深,我用过别人写的分配内存的函数,但是自己确实没有动手设计过一个,所以没有太多体会。但是如果以后设计的话,必须遵守下面几点:
1行为要和系统的new一致
2返回值正确
3 内存不够的时候,调用出错函数
4处理好0字节问题
5避免不小心隐藏保准new

其他的地方,我自己理解的不深刻,大家自己看看书吧。

条款9: 避免隐藏标准形式的new


这条我也没有经验,不敢耍大刀。
函数隐藏可以解释一下,就是局部函数或者局部变量,会隐藏全局函数或者全局变量。
就直接拿书上的例子,方法就是要重新写一个new函数和系统的一样

class x { 
public: void f();
static void * operator new(size_t size, new_handler p);
static void * operator new(size_t size) { return ::operator new(size); } 
};
x *px1 = new (specialerrorhandler) x; // 调用 x::operator // new(size_t, new_handler)
x* px2 = new x; // 调用 x::operator // new(size_t)

这里就解释一下重定义操作符的含义,比如我们重定义,+,-,*,/四则运算符号,那么后面跟的两个参数就是在这四个符号两边的。
如果我们定义单目操作符,例如负号-,那么我们后面只用跟一个参数。

这里 new后面跟两个参数,一个是用来告诉大小的,另一个是异常处理,(这里理解成回调函数,不知道理解的是否有误差)

条款10: 如果写了operator new就要同时写operator delete


这里面写了一个内存池的概念,我觉得这个很好,什么叫内存池,它的优点在哪里呢?

我举个例子,比如我们的程序会定时的处理一些数据,这些数据的大小是40M到80M。
我们怎么处理这些数据呢?
while(1)
{
申请空间------------>处理数据----------------------->释放空间
}

你会发现如果这个内存很大,而且调用频率很频繁,那么你大部分的时间都耗费在申请和释放空间上面了。
怎么提高效率呢?
处理数据这里去提高么?但是再怎么优化都有一个极限。

下来我们能考虑的就是内存上面的。
画个图来表示吧,画图最能说明问题,但是确实很累。。还没钱,所以还望大家见谅。

                           

上图是两次内存分配的情况,对于这种问题,我先分配80M空间出来,然后第一次使用40M,第二次使用前不用释放再申请,如果是整体覆盖的形式memcpy整块复制的话,我们什么都不需要做,如果是部分数据复制,我们要把这一块使用的60M初始化为0.
其实你如果重新申请空间的话,这一步也是不可避免的。

所以,我们把所有的空间申请和释放的中间过程省略了,只需要在不再使用的时候去释放就可以了。

这里提示一下,我们这个场景的适用性需要多多考虑,多多注意。
1 使用频率很高。
2 内存占用不会影响其他模块,最大内存是可知的。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值