一、面向对象编程
面向对象编程是几乎所有开发者都要面对的最基础的开发方式之一。或者可以这样说,现在的编程不管叫面向什么编程,面向对象编程都是重要的基础。除非使用一些函数式编程语言,不再有对象的概念。
在C++编程中,面向编程的最基础的一点就是封装,也就是类的封装。有了类,自然就要有类对象的产生机制,这就是构造函数;当然也要有类对象的回收机制,也就是析构函数。
二、构造函数和析构函数
在本文不讨论构造函数和析构函数的原理和重要性,只谈一点,即如何在两种函数中,保证类对象的安全的创建出来或安全的回收回去。先谈谈构造函数,很多开发者在实际开发时,经常遇到的情况是,在函数内部进行大量初始化动作(当然包括列表初始化等)。这种动作结果如何,对整个构造函数能否顺利工作非常重要。同样,在析构函数中也是如此。
这里面有几种情况:
1、基础类型的参数初始化
这种情况理论上不会出现什么问题,可以大量的赋值。
2、简单类(结构体)对象的初始化
这种情况出问题的可能性也微乎其微,可以不用考虑。
3、复杂类(含模板)对象的初始化
这种情况就相当复杂了,假如有大内存的创建、拷贝这事儿就极有可能出问题。如果有内存访问还有可能越界等等。这些都非常可能导致构造函数和析构函数的异常。
4、资源的初始化
这种情况同样复杂,比如一个句柄被另外一个进程或线程锁住,一个资源还没有被释放就又去访问,就会导致构造函数和析构函数的异常。
5、函数的执行
函数的执行有很多种情况,一种是类似1和2这种简单的处理函数,只是为了设计的处理仍然没有问题,但如果函数执行中有3和4这种情况,同样是有问题的。另外,如果函数执行了一些递归等动作同样会导致构造函数和析构函数的异常。
6、其它
如类有继承情况,那么对析构函数来说,很可能会出现资源泄露,最简单粗暴的方式就直接给一个virtual。虽然在前面提到过,哪几种情况不需要使用virtual,但谁也不敢保后来维护者会搞大事情,所以这样做更安全一些,毕竟大多数的应用不会关注这么一点点性能的损失。
而构造函数则不能加virtual,因为有可能导致构造的失败,毕竟一开始创建一个对象得知道它是谁该调用谁,而不是动态绑定后再生成对象,黄瓜菜都凉了。
上面的这些问题,都是客观存在的,开发者没遇到过,不代表不会发生,发生了怎么办?总不能装做不知道吧。
三、比较实际的处理方式
一般来说,解决问题时,大家总想着最好的方法,但目前看来,解决这类问题没有最好的方案,只有一个折衷的方案。解决问题虽然既能又能还能最好,但“世上安得双全法”,单纯就解决这种能顺利的构造和析构来说,目前没有特别好的解决方式。在内部使用异常处理显得太粗暴太丑陋了。
目前来看,容易被理解,简单并行之有效的方法是使用一个类似init(或uninit)的函数来专门处理上述的情况。即在构造或者析构函数中,只做最基础的工作,比如上面的在析构函数前加virtual或者非常简单的1或2这种行为。
然后在对象创建后,专门调用这个init函数进行相关的资源初始化,并在对象生命周期结束前,调用uninit函数释放相关的资源。它很简单,也容易做到,但确实是让开发者感觉有些微微的不爽。不过,真得没有好办法。如果类对象的创建没有复杂的对象(包含内存或资源等的处理),那就无所谓,如果有,还是强烈建议这样做。
四、总结
总说成年人要学会退让,其实开发过程中也是如此。有失才有得,有得才有失。开发程序既是一个技术问题也是一个人情故的问题。还是那句话,万法相通,能不能明白就看各自的悟性!

502

被折叠的 条评论
为什么被折叠?



