`
yhailj
  • 浏览: 35041 次
  • 性别: Icon_minigender_1
  • 来自: 浮云
文章分类
社区版块
存档分类
最新评论

C++不垃圾,只是Java很傲慢

阅读更多
以下内容为转载: http://my.oschina.net/alphajay/blog/3859

《Thinking in C++》及《Thinking in Java》的作者Bruce Eckel向来是个“拥C++反Java”派,他曾经不止一次的提到,C++语言特性的添加有多么的深思熟虑,而Java又是如何的把一些奇怪的东西不停的加进去。Bruce认为,理解语言特性为什么会存在是非常有帮助的。他将其称之为“语言考古学”。

在C++委员会会议上我所能找到的,是C++社区里最聪明的一群人,群英荟萃,为我答疑解惑。我很快意识到,这种方式之好,远超我在任何一门研究生课程中之所得。如果考虑到研究生的机会成本,这还是一笔在财务上要划算得多的生意。

我被深深吸引住了,坚持出席了有大约8年的时间。在我走后,委员会仍继续前行;虽标准仍未制定完成,但彼时Java已经出现了,还有一些其他(语言)的草案也问世了(这是技术刺激成瘾者的毛病——我的确钻研某一门语言,但我也一直在寻找更有生产力的手段:那些前景看起来很光明的语言特性可以毫不费力地分散我的注意力)。

每次大家见面的时候,我都会抛出一列清单,这是我累积下来的有关C++的棘手问题列表。通常我会请他们在几日内予以澄清。出席委员会能看到的最有价值的东西就是这个,当然,还包括得以早早接触到即将公布的新特性。

从长远来看,把语言特性添加进C++的谜团里面并观察它,是一门深奥的学问。现在说三道四是一件很简单的事情,说什么C++太烂了,设计太糟糕了等等。在对C++设计时所受的约束都没有任何理解时,很多人就这样脱口而出了。Stroustrup(这个Stroustrup也就是邀请作者参会的Stroustrup,也就是C++语言的设计师Stroustrup)的约束是,C程序应该稍作改动,或者最好不做改动,就能在C++下编译。且不管这是不是完全合乎逻辑,但它给C程序员提供了一个很好的演进路径。不过这存在较大的局限性,需要把每一项大家抱怨不已的困难特性都一一虚拟化。由于这些特性难以理解,许多人就直接得出结论说C++设计糟糕,而这远非事实。

在语言设计上,Java用傲慢的态度对待这一认识。关于这一点,我在《Java编程思想》及许多博文上都写过了。因此我的长期追随者都知道,由于
Gosling(Java语言之父)和Java语言设计者对C++的否定态度,Java一开始就把我拧到了错误的方向。说实话,我与 Gosling 的首次“邂逅”印象糟糕——那是很多年以前的事了,当时我刚进入第一家公司,第一次开始使用UNIX (Fluke,生产电子测试设备;我在里面做嵌入式系统编程)。有一位软件工程师辅导我,教我使用emacs。不过当时公司里唯一的工具只有Gosling Emacs的商用版(Unipress)。如果你做错了什么,程序会侮辱你,把你叫做火鸡,并把屏幕填满垃圾。这样的东西出现在了一个商用产品上,而我们公司可是花了相当一笔钱的。不消说,等到Gnu emacs变得稳定起来后,公司马上就换到了Gnu emacs上(我见过Richard Stallman。当然,他是个疯狂的家伙。不过他也是绝顶聪明的:他知道当遇到麻烦的时候,你需要的是帮助,而不是羞辱)。

我不知道对Gosling印象的这段形成经历在多大程度上影响了我后面对他工作的看法,但事实上,“我们看见它太差劲了,就决定拿出自己的语言”,对C++的这种态度于事无补。尤其是当我开始在《Java编程思想》的写作过程中把它弄清楚,并屡次发现,那些草率决定的语言特性与库,都不得不予以修订——确实如此,其中的大部分都必须要修订,有些修订还是在程序员已经忍受了多年之后才落实。在许多场合下,Gosling坦诚他们必须快马加鞭,否则就要被互联网革命超越了。

我发现,理解语言特性为什么会存在是非常有帮助的。如果是由大学教授一下子和盘托出,把它们端到你面前,你势必就会构想出这门语言的一个神话,说“
这种语言特性之所以存在,肯定有一些真正重要的原因,这些原因只有创建这门语言的聪明人才能理解,我是理解不了的,我信赖它就是了”。从某方面来说,对语言特性这种基于信仰的接受是一种负担;它阻止你对所发生的事情进行分析和理解。在我的主旨演讲中,我会关注一些特性,并检查一下它们在不同语言中是如何被实现的,以及为什么被实现。

这里就有个例子。对象创建。在C语言中,声明了变量之后编译器就会为你创建堆栈空间(未经初始化,除非你初始化,否则会有垃圾数据)。但是如果你想要动态地做这件事情,你就得使用 malloc() 和 free()这两个标准库函数,还要小心翼翼地手工执行完所有的初始化及清理工作。如果你忘了,就会出现内存泄漏等类似灾难,这是常有的事。


有关动态对象创建:一般来说,编译器将内存分为三部分:静态存储区域、栈、堆。静态存储区主要保存全局变量和静态变量,栈存储调用函数相关的变量、地址等,堆存储动态生成的变量,在c中是指由malloc,free运算产生释放的存储空间,在c++中就是指new和delete运算符作用的存储区域。

因为malloc() 和 free() “仅仅”是库函数,在基本编程课上,应有的相关知识通常没有被传授,令人既疑惑不解又胆颤心惊。当程序员需要分配大量的内存空间时,他们就不去学如何来使用这些函数进行处理,取而代之的是常常就分配一个巨型数组的全局变量了事(不是开玩笑),数组之大,远远超过他们曾自认为所需的空间。程序似乎工作了,再说了,好像谁都不会用到产生越界——因此,当多年之后它的确发生的时候,程序中断了,而某个可怜的家伙就得一头钻进去,把错误在哪里这个谜底给找出来。

Stroustrup认为动态分配需要更简单、更安全——这一块得放到语言核心中,而不是降格为库函数。还必须要与初始化和清理一起协同工作,初始化和清理必须由构造函数和析构函数分别提供,以便为所有对象提供相同的保证。

这个问题是影响了全部C++决策的一块里程碑:对C的向后兼容性。
理想情况下,对象的堆栈(heap)分配可只需忽略即可。但C的兼容性要求进行堆栈(stack)分配,因此必须对heap对象和stack对象进行区分。为了解决这个问题,C++从SmallTalk挪用了new 这个关键字。创建 stack 对象只需声明即可,像这样: Cat x;或者带参数的情况下, Cat x("mittens");。而创建heap 对象时,就使用new,像这样: new Cat x; 或者 new Cat x("mittens");。利用这个约束,我们得到一个优雅而一致的解决方案。

自从判定C++的一切都做得不好且过于复杂之后,Java就产生了。具有讽刺意味的是,Java 决定把 stack 彻底抛弃了(特别是忽略了基本类型上的失败,这点我已经在别的地方指出过了)。真好啊,既然所有对象都是在heap上分配的,区分stack和heap的分配就没有必要了。他们可以轻易说 Cat x = Cat() 或者 Cat x = Cat("mittens")。或者甚至更好地,用联合的类型引用来消除重复(不过那样——还有像闭包(closure)之类的其他特性——就显得“太长”了。因此我们反而离不开Java的平凡版;类型推导已经讨论过了,但我敢打赌那不会发生,也不该发生。因为这会在给Java增加特性的同时带来问题)。

Guido Van Rossum (Python的创建者)采用了一个最小化的方案——经常为人所痛斥的空白的使用,正说明了他对语言简洁性的追求。既然 new 关键字不再必要,他就省去了,好像这样: x = Cat("mittens")。Ruby 也可能用了这种方法,不过Ruby其中一个主要的约束是尽可能追随Smalltalk,因此在Ruby是这样的:x = Cat.new("mittens") 。但Java以贬低C++做事的方式为准则,以至于用了new 这个关键字成了一个谜了。自研究了该语言在其他地方所做的决策后,我的猜测是,
他们是不是从来就没有意识到,这东西根本就是可有可无的

因此这就是我所说的语言考古学的意思。我希望人们能用一个更好的视角来看待语言设计,并在学习一门编程语言时,能有更多的批判性思维过程。
分享到:
评论

相关推荐

    C++只是Java很傲慢

    ### Bruce Eckel的观点:C++的深思熟虑与Java的傲慢 Bruce Eckel,《Thinking in C++》和《Thinking in Java》的作者,对于这两种语言有着独特的见解。他认为C++的每一次语言特性的添加都是经过深思熟虑的,旨在...

    C++代码转java工具

    至于压缩包内的文件“C++ to Java Converter.exe”很可能就是这个转换工具的执行程序,用户可以通过运行这个程序来转换C++代码。而“1.txt”可能是工具的使用指南、示例代码或转换后的Java代码。 在实际使用这种...

    C++转换JAVA工具

    这个过程可能涉及到一些挑战,比如C++的模板、指针和运算符重载在Java中的映射,以及Java特有的垃圾回收机制与C++手动内存管理的差异。工具需要确保转换后的代码不仅语法正确,而且能保持原有的功能和性能。 安装...

    C++转Java工具

    例如,C++的类会被转换为Java的类,指针会映射到Java的对象引用,C++的动态内存管理会被转换为Java的垃圾回收机制。 在描述中提到的,这个工具对JNI开发很有帮助,意味着它可能能够帮助开发者更容易地将C++的本地...

    C++调用Java方法

    Android Studio项目,此Demo实现Java调用C++函数,然后C++函数回调Java方法、纯C++直接调用Java方法,此为github地址链接

    CPlus_to_Java_Converter;C++转java工具

    转换器需要将C++的指针操作转换为Java的引用操作,同时处理内存分配和释放的差异,因为Java的垃圾回收机制会自动管理内存。 2. **面向对象的差异**:C++支持多继承,而Java只允许单继承。转换器需要适当地重构多...

    Java转C++代码工具 J2C

    4. **跨平台兼容性**:虽然Java有很好的跨平台性,但在某些特定环境下,C++可能是更好的选择。 然而,转换过程并非总是无缝的。Java的动态性和灵活性在某些情况下是其优势,但在C++中可能需要额外的编程工作来实现...

    从java到c++,适合java程序员快速学习c++

    C++ 字符串是可以被修改的,而 Java 字符串的内容是不可修改的。 3. 取子字符串的操作在 C++ 中叫做 substr。 4. 在 C++ 中,你只能够将字符串与其它字符串对象相串联,而不能够与任意的对象相串联。 5. C++ 中...

    C++ 垃圾代码生成器

    2. **垃圾代码的概念**:垃圾代码指的是没有实际功能或逻辑错误的代码,它不执行任何有用的工作,但会占用内存和CPU资源。在测试中,垃圾代码可以用来测试程序的容错性和性能极限。 3. **C#编程语言**:虽然标题中...

    java调用C++ webservice

    在IT行业中,跨语言通信是常见的需求,尤其是在Java和C++这样的不同编程环境中。本话题主要探讨如何使用Java调用由C++实现的Web服务(Webservice)。在给出的描述中,提到了通过WSDL(Web Services Description ...

    C++库封装JNI接口-实现java调用c++

    在跨平台的软件开发中,有时我们需要在Java和C++之间进行交互,这通常是由于性能需求、使用已有的C++库或特定硬件接口的原因。Java Native Interface (JNI) 是Java平台提供的一种机制,允许Java代码和其他语言写的...

    在Qt平台C++和Java代码的交互

    总结来说,Qt平台上的C++与Java代码交互涉及到JNI接口的使用,包括C++函数的声明、Java方法的调用、动态库的加载以及在Qt项目中的整合。熟练掌握这些技巧,将有助于开发跨语言的复杂应用程序。在实践中,应不断学习...

    C++与java比较

    函数参数方面,Java不支持默认参数,这意味着每个函数调用都需要提供完整的参数列表,而C++则允许设定默认值,简化函数调用。在代码组织上,Java更倾向于纯面向对象,所有代码都包含在类中,而C++可以同时使用函数和...

    C++头文件转JAVA JNA接口类

    在IT行业中,跨语言通信是常见的需求之一,尤其是在Java与C++之间。为了实现这种通信,我们可以使用Java Native Access(JNA),它是一种无需编写原生代码就能直接调用操作系统API或其他本地库的Java库。本篇文章将...

    c++ 转换 java c# 转换 java c++ 转换 c#

    转换时,C++的类需要映射到Java的类,指针通常会转化为Java的引用,而内存管理则从手动管理(C++的new和delete)转变为自动垃圾回收(Java的GC)。`Free Edition CPlusPlus to Java Converter.zip`可能是一个工具,...

    java/c++区别

    1) **JAVA摒弃的C++内容**:Java不支持指针,以减少内存错误,且没有全局变量和goto语句,增加代码的可读性和安全性。 2) **JAVA的新特性**:Java引入了垃圾回收机制,自动管理内存,简化了程序员的工作;并且提供了...

    C++ to Java Converter

    超强的C++ to Java转换工具!!希望对大家有帮助。无污染。

    从C++编程转到Java编程.rar

    在从C++转向Java的过程中,开发者需要适应Java的类加载机制、垃圾回收机制和更为严格的类型系统。同时,熟悉Java的异常处理和并发编程模型也是关键。此外,学习并利用Java的标准库,如集合框架和网络编程API,能够...

Global site tag (gtag.js) - Google Analytics