现代程序设计——homework-07

时间:2024-04-30 19:04:14

1、写在前面

  不得不很惭愧地说,在看这些博客之前,我对C++的了解仅限于上过一门特别水的关于C++的公选课、一门只有五节课的专业选修课,写过一点点符合C++语法语法规则的类C程序,偶尔在论坛、博客中看到C++的代码。最近一次接触C++是10月28号,翘掉了现代程序设计课,去听了Stanley B.Lippman的讲座,以挂掉一次课堂作业的代价复习了一点点C++程序设计语言的入门知识。这就是我关于C++的全部家底。

2、阅读过程

  我阅读的过程基本上是按照老师博客中连接的顺序来的,顺次阅读链接中的内容,点开链接中自己关心的链接,Google链接内容中自己不懂的名词。

  <1>MSDN文档

    http://msdn.microsoft.com/en-us/library/hh279654.aspx

    文档的重点在“Modern C++”上,个人感觉C99出来之后,C更像C++了,Modern C++更加Plus了解决了一些Java程序员所诟病的点。于是新版本的C++就有了一下几个比较受重视的新特性:

    1、C++标识符的作用域是基于栈的,这个东西实在是不明觉厉,我的理解是C++编译的符号表是分配在栈空间的;

    2、使用自动类型推断代替显示类型名,瞬间安全性提高的感觉;

    3、支持智能指针,这貌似是一个时时版的GC;

    4、升级了字符串库,可以不再使用字符数组的节奏;

    5、升级了标准模板库,看起来很高大上;

    6、支持异常处理,脱胎换骨的感觉;

    7、C++的库真得是名不虚传(对于一个C Programmer),还提供各种算法模版;

    8、规范化线程通信;

    9、内联lambda函数精简代码;

    10、升级版for循环,搞得跟JavaScript似地,难道老版本的for循环也是C++的槽点么?

    其中我比较感兴趣的是第一、二、三、四、五、九条。

  <2>Stack-based scope instead of heap or static global scope;

    我没有找到太多关于这条的信息,尤其是这些关于IDE的文档中,几乎找不到痕迹。我也没有发扬革命精神深究一下,概率算法猜测一下,这是一个关于C++语法树存储的改进,统一了C++语法树的位置,提高了编译C++程序的效率。如果我猜对了,我第三个想问的问题是:

    (3)这个底层是怎么搞得?

    如果我猜错了,我第三个想问的问题是:

    (3)这个新特点是什么意思?

  <3>自动类型推断

    想要搞清楚这个东西需要先搞明白C++的explicit关键字、类型推断、动态类型、静态类型,这里不做解释,详见链接中各位神牛的解释

    explicit:http://wenku.baidu.com/link?url=hV9VgmmIq2ICT-9HOZrWeZYnFXRYeJ9RYb4Nb3SGYwBI6yAzZFeEq5Wo_V1jciujLVwlEcjBb7T-lS1gB8Mwjn_Kn7qPWprt4Ti3QohhN4S

    类型推断:http://en.wikipedia.org/wiki/Type_inference

    动态类型和静态类型:http://perhaps.cnblogs.com/archive/2005/08/02/205650.html这篇博客的亮点在评论中。

    概括一下:explicit是在一定程度上防止对象构造的隐式转换的;动态类型相对于动态语言,在这些语言中变量没有特定的类型,你付给它什么类型的值,它就是什么类型的变量;相对的就是静态类型,C族语言都是静态类型的;类型推断就是在静态语言中搞一个类似于动态语言的变量,在程序运行过程中不断分析表达式的类型,最后给它确定一个类型。

    这种处理方式,对于类型转换,我们是可以看见的,我们知道那是一个auto,我们知道他的类型是在变的,而不是像之前那样,它的类型没有变,内容却不再是我们期望的内容。

    想要了解更多内容,并查看样例,请转入这个博客

    自动类型推断auto和类型获取decltype

    http://blog.****.net/srzhz/article/details/7934483

    关于自动类型推断,有我关心的第一个问题:

    (1)这样做是在赤裸裸地牺牲效率,运行的效率,有什么好处?

  <4>新的字符串模版

    我对这个新特性没有什么太多想说的,对它产生兴趣源于无意中点开了MSDN中<string>的链接

    http://msdn.microsoft.com/en-us/library/hd5zecz6.aspx

    再operator中,看到有“+”这个操作符的时候,我还是很吃惊,问了问“轩爷”,貌似这个东西很久以前就有了,确实更新的重点也不在这里。出于我自己在搞GCC源码阅读的内容,并且对于GCC中C语言动态内存分配的处理很是拙计。我对GCC的理解,GCC在编译C程序时,字符串是要分配到堆中。当然听过lippman先生讲解C++模型的建立过程,感觉他处理这个问题,还是轻松加愉快的,可是C++不出意外是完全兼容C的,我猜它的字符串也是放到堆中的。假设我的猜想是对的,那么,我的第四个疑问:

    (4)在处理字符串加运算时,比如:stringa=stringa+stringb,内存中是怎么运作的;

      我的想法是:

      方案一:硬拼接,stringa占用空间后面接跟着加入stringb的内容,操作系统如果没有提供处理stringa之后没有足够空余空间放置stringb的内容的情况,手动处理之,把后面的东西顺次向后压,把后面的闲置空间挤出来。

      方案二:寻找一块能够放置加操作结果的空间,如果有,万事大吉;没有,再去挤一挤。

  <5>Lambda Expression &Lambda Function

    第一次听说这个东西,扫了一眼MSDN的介绍

    http://msdn.microsoft.com/en-us/library/dd293608.aspx

    看得不太明白,翻了翻其他的博客,感觉这个博客解释得还不错,充分照顾了我们这些没有熟练使用过C++的感情,

    http://blog.****.net/srzhz/article/details/7934652

    瞬间感觉好是一个高大上啊,说简单点,就是一个新版本的无名函数。以前C++是用函数对象和函数指针来实现无名函数这个编程技巧的,当然,这两个家伙不是尽善尽美的,实现函数对象的开销太大,函数指针没有保留状态的能力。对于函数指针的缺点,我想说函数指针是一个定义在一定范围内的变量,需要指向一个特定模式的函数才能用,而Lambda函数在这个方面是比较灵活的,准备用一用再看看具体区别到底在什么地方。

    感觉这个东西真心很好,不过度过激动期之后马上感觉不对头,这个东西确实很实用也很花哨,而且看起来不仅增加了代码的灵活性,还增加了可读性。但是,当你面对一个百万行代码量级满是这种自动类型推断的工程的源代码时,你不会像现在这样仅仅是疯掉这么简单,至少如果我遇到这种事儿,我会变得想死的心都有的。那么,考虑一下灵活性,于是又有一个问题:

    (2)这种自动类型推断会不会让一些BUG变得很难发现?我想是的,那么这帮老爷爷们搞这个东西“能”“好”?

    看遍了MSDN中

    http://msdn.microsoft.com/en-us/library/dd293599.aspx

    关于Lambda Expression的样例,这个东西确实很是一个强大,也不枉MSDN中列出了那么多优点,也许这就是一个“鱼和熊掌不可兼得”的问题吧。

  <6>右值引用

    C++11中的右值引用确实看起来很清新的感觉,想要理解这个东西需要先搞清楚什么是右值什么是左值,这两个东西的区别说得简单一点就是对于在表达式中出现的值,有的值在表达式执行过后就消失了,被消化掉了。其实具体是什么我也没有明白,那么右值引用呢?就是C++的引用类型本来只能引用左值,因为你如果允许引用一个右值会出问题的。本来嘛,你很高兴的搞到了一个高仿货,本来想好好用的,结果半路找不到爹了,这可不好整了。

    但是,右值引用的诞生跟这个一毛钱关系都没有,它是为了实现完美转化而生的,什么叫做完美转发呢?C++中的变量是可以按照const、non_const和左值、右值进行分类的,于是结合这两种分类方法后,C++中的变量是有四类的,当我们在一个函数中使用该函数的参数作为参数去调用另一个函数的时候,我们需要保证这两个参数在两个函数中的类型是一致的,能够实现这个诉求就叫做完美转发。

    上一版C++之所以不能很好地支持完美转发,是因为现在C++目前关于引用的绑定类型限制问题,const Type&是不能绑定非const的值的,Type&是不能绑定右值的。这就造就了一对矛盾,你要么选择const保证右值正常转发,要么选定non_const保证左值正常转发,要么把每个参数重载一下让左值右值正常转发。

    于是新版本的C++搞出来一个新的规则,引用一篇博客的解释“如果实参是左值,那么T就被推导为U&(其中U为实参的类型),于是T&& = U& &&,而U& &&则退化为U&(理解为:左值引用的右值引用仍然是左值引用)。如果实参是右值,那么T就被推导为U,于是T&& = U&&(右值引用)”

    详细解释,参考如下几篇博客的相关部分:

    http://zhangjunxin520.blog.163.com/blog/static/3050370320116210101891/

    http://blog.****.net/hzyong_c/article/details/8273884

    http://blog.****.net/pongba/article/details/1697636

    第三篇博客解释得比较详尽清楚,但是顺序看下来三篇博客,你会有更多的收获。

3、阅读感受

  曾经我很纠结这个问题,C++不能干什么?为什么C++不能应用到这些领域中去?在一个帖子中我解开了这个心结“If it can do everything, it can't do anything well”。我眼中一个比较合理的模式是“花5000个小时广泛涉猎一个领域的相关内容,再花5000个小时钻研一个自己喜欢的分枝”,对于一个想在一个领域有一点造诣的人。就像我在学习这些新特性时翻的众多帖子的主人,我感受到了他们身上的专业气质。

  正值“改革”这个词、这项工作又被提到桌面的时代,我们没有理由不去思考“怎么样进行改革”的问题,这是我的第五个问题

  (5)改革中如何做出选择?

  这似乎是一个无法通过理论得到结果的问题,只有真正拿到选择的结果,我们才能知道选择的对错。就像C++11中的许多新特性,好多都是双刃剑,都需要决策者在手心手背之间进行取舍。如果我能知道决策改革的人是怎么想的,那该多好。

  我这篇博客是边看边整理修改的,问题出现得比较随意,下面是所有的五个问题:

  (1)自动类型推断是在赤裸裸地牺牲效率,运行的效率,为什么要这么做?

  (2)这种自动类型推断会不会让一些BUG变得很难发现?我想是的,那么这帮老爷爷们搞这个东西“能”“好”?

  (3)编译器关于“Stack-based scope instead of heap or static global scope”的底层实现是什么样的?

  (4)在处理字符串加运算时,比如:stringa=stringa+stringb,内存中是怎么运作的?

  (5)改革中如何做出选择?