C++沉思录随笔
话说书非借不能读~~好象也有点道理,家里买了好几本书都一直以没时间为由读得不多,还有两本被俺压在坐位下面当垫子用了~~ 而事实上是并非时间不够而是没有善加利用罢了~~看来以后得改进一下. 正好同事借了一本C++沉思录就随手拿来看看,没想到一发不过收拾,一口气看完了,仅仅用了一天时间. 虽然是囫囵吞枣式的读过来但还是大体领会了一些核心思想.
书是个老外写的,具体啥名字记不得了,不过翻译质量还不错,没有发现太多的语病. 读起来也比较流畅. 好了,废话不多说了,下面转入正题.
计算机语言发展到C的时代已经比较后来的事情了,C语言作为一门优秀的计算机语言而被广泛地使用着,然尔它在提供了足够灵活强大的功能同时也带来了不少的麻烦,最典型的要算是内存的分配与回收了,这个问题可以说是贯穿了本书的一个核心问题. 几乎一切问题的根源均来源于此. 因为在C语言中程序员需要自己管理内存的使用,何时分配何时释放就显得特别重要,而C语言又引入了指针这么一个概念,由此即可引发一系列的问题:
因为指针是指向某个内存地址的一个标识. 如果它指向的这个地址已经不再是指针本身限定的对象是就会引发不可知的后果造成程序崩溃.
如果分配的内存没有及时释放会造成内存占用不断上升,以至于系统运行一段时间后当机.
对于集合而言, 值引用与地址引用的语义差异不论对于系统框架的设计者或是程序开发人员而言都是比较麻烦的事. 比如我们在将一个对象添加进一个集合之后, 我们再改变这个对象的属性时集合中的对象需不需要反映这个对象的当前状态? 在某些情况下我们可能需要它同时更改,但在另外一些场景下我们可能希望这个原对象与集合里面的这个对象是两个不同的单位, 集中里那个只不过是在添加时产生的一个克隆体,在此后的时间里面它们的状态将可以独立改变而不互相影响.
如果是地址引用,那么当这个原始对象失效的时候,那么集合里面的引用地址将指向一个无效的内存地址, 除非你显式地去更新这个集合对象,但问题我们有时候很难去维护这种关系.
对于值引用而言, 如果对象里面还包含有子对象,那么 这个时候又将怎么处理呢?
为了制作这样一个合适的集合即我们的容器,又有一些新的思想被提出来,比如对象引用计数,Handle技术等等处理方式. 为了更一步把算法和数据结构抽象出来于是又有了STD库这样的东西(类似于C#的泛型技术). 当然这里还需要考虑一些诸如给调用代码什么样的接口, 错误处理机制等. 如什么样的东西应该隐藏在内部实际,什么东西应该由客户代码去处理.
还有一个重要东西就是动态的内存地址分配,因为象数组这种东西它的容量是相对固定,如果需要改变它的大小就需要重新分配内存,而我们有时候很需要一个容量可以动态变化的这样一个容器. 这就需要将内存这部分冗长工作的复杂性通过某种数据结构隐藏起来.
了解了C++的这些内容之后再回过头来看C#,你会发现用C#是那么的舒服,因为有很多事情CLR都帮你去完成了,比如内存空间的分配,对象何时从内存中移除(它会进行自动对象引用计数, 归零时即有可能被GC回收)等等问题, GC在里面发挥了重要的作用. 这让我想起了黑客帝国里面的场景:对于身处系统中的人,你可能什么都感觉不到,你甚至感觉不到“系统”的存在,但是当你突破了这层限制你就会看到另一个世界.
然尔通常的看法是C++并不因它的复杂性而被淘汰,“它更象一些精巧的工具”, 你可以用它制造一些精密的结构或用于制造其它工具, 它可以长时间稳定而高速地运行, 而象C#,它让人更多地考虑功能逻辑的实现,让程序员从繁杂的内存管理工作中解脱出来,从而也避免了很多犯错误的机会. 虽然牺牲了一部分性能作为代价,但在很多情况下都是可以接受的,何况在今天这种硬件计算速度高速增长的时代里.
"复杂性不可避免, 但是应该将这些复杂性向更高的抽象层次隐藏起来", 这当然是大势所趋,而C#正是因此诞生。正如计算机,就单个部件来讲,其实它们自身已经具有相当的复杂性了,想想当年的计算机,动辄几间房那么大,现在可以作得这么小,就在于它将它的内部复杂性很好地隐藏起来,作为用户来讲我们不用关心它的具体实现, 不论是三星的硬盘还是西捷的硬盘,无论是闪存还是SCSI都可以完成我们的存储需要. 也正是这样我们才可以在此之上构建一些更高级的结构.
总而言之,内存管理是C/C++程序员的痛苦根源.
书是个老外写的,具体啥名字记不得了,不过翻译质量还不错,没有发现太多的语病. 读起来也比较流畅. 好了,废话不多说了,下面转入正题.
计算机语言发展到C的时代已经比较后来的事情了,C语言作为一门优秀的计算机语言而被广泛地使用着,然尔它在提供了足够灵活强大的功能同时也带来了不少的麻烦,最典型的要算是内存的分配与回收了,这个问题可以说是贯穿了本书的一个核心问题. 几乎一切问题的根源均来源于此. 因为在C语言中程序员需要自己管理内存的使用,何时分配何时释放就显得特别重要,而C语言又引入了指针这么一个概念,由此即可引发一系列的问题:
因为指针是指向某个内存地址的一个标识. 如果它指向的这个地址已经不再是指针本身限定的对象是就会引发不可知的后果造成程序崩溃.
如果分配的内存没有及时释放会造成内存占用不断上升,以至于系统运行一段时间后当机.
对于集合而言, 值引用与地址引用的语义差异不论对于系统框架的设计者或是程序开发人员而言都是比较麻烦的事. 比如我们在将一个对象添加进一个集合之后, 我们再改变这个对象的属性时集合中的对象需不需要反映这个对象的当前状态? 在某些情况下我们可能需要它同时更改,但在另外一些场景下我们可能希望这个原对象与集合里面的这个对象是两个不同的单位, 集中里那个只不过是在添加时产生的一个克隆体,在此后的时间里面它们的状态将可以独立改变而不互相影响.
如果是地址引用,那么当这个原始对象失效的时候,那么集合里面的引用地址将指向一个无效的内存地址, 除非你显式地去更新这个集合对象,但问题我们有时候很难去维护这种关系.
对于值引用而言, 如果对象里面还包含有子对象,那么 这个时候又将怎么处理呢?
为了制作这样一个合适的集合即我们的容器,又有一些新的思想被提出来,比如对象引用计数,Handle技术等等处理方式. 为了更一步把算法和数据结构抽象出来于是又有了STD库这样的东西(类似于C#的泛型技术). 当然这里还需要考虑一些诸如给调用代码什么样的接口, 错误处理机制等. 如什么样的东西应该隐藏在内部实际,什么东西应该由客户代码去处理.
还有一个重要东西就是动态的内存地址分配,因为象数组这种东西它的容量是相对固定,如果需要改变它的大小就需要重新分配内存,而我们有时候很需要一个容量可以动态变化的这样一个容器. 这就需要将内存这部分冗长工作的复杂性通过某种数据结构隐藏起来.
了解了C++的这些内容之后再回过头来看C#,你会发现用C#是那么的舒服,因为有很多事情CLR都帮你去完成了,比如内存空间的分配,对象何时从内存中移除(它会进行自动对象引用计数, 归零时即有可能被GC回收)等等问题, GC在里面发挥了重要的作用. 这让我想起了黑客帝国里面的场景:对于身处系统中的人,你可能什么都感觉不到,你甚至感觉不到“系统”的存在,但是当你突破了这层限制你就会看到另一个世界.
然尔通常的看法是C++并不因它的复杂性而被淘汰,“它更象一些精巧的工具”, 你可以用它制造一些精密的结构或用于制造其它工具, 它可以长时间稳定而高速地运行, 而象C#,它让人更多地考虑功能逻辑的实现,让程序员从繁杂的内存管理工作中解脱出来,从而也避免了很多犯错误的机会. 虽然牺牲了一部分性能作为代价,但在很多情况下都是可以接受的,何况在今天这种硬件计算速度高速增长的时代里.
"复杂性不可避免, 但是应该将这些复杂性向更高的抽象层次隐藏起来", 这当然是大势所趋,而C#正是因此诞生。正如计算机,就单个部件来讲,其实它们自身已经具有相当的复杂性了,想想当年的计算机,动辄几间房那么大,现在可以作得这么小,就在于它将它的内部复杂性很好地隐藏起来,作为用户来讲我们不用关心它的具体实现, 不论是三星的硬盘还是西捷的硬盘,无论是闪存还是SCSI都可以完成我们的存储需要. 也正是这样我们才可以在此之上构建一些更高级的结构.
总而言之,内存管理是C/C++程序员的痛苦根源.