作者:幻の上帝

出处:http://hi.baidu.com/frankhb1989/item/185f0a14823dd1f8dceeca2c

此文硬伤不少,且相对谭XX的书而言隐晦许多,不建议新手学习。
主观的论述,合理的部分,就此略过。疏漏之处也尽量忍住不吐槽。

第1章 文件结构

每个C++/C程序通常分为两个文件。

//错误。没有强调翻译单元的概念。

另一个文件用于保存程序的实现(implementation),称为定义(definition)文件。

//有误。实现不简单等同于定义。例如,类的完整声明也是类的定义,但不是完整的实现。头文件也可以存放其它定义(例如模板和内联函数的实现)。

1.2
建议1-2-1

在C++语法中,类的成员函数可以在声明的同时被定义,并且自动成为内联函数。这虽然会带来书写上的方便,但却造成了风格不一致,弊大于利。建议将成员函数的定义与声明分开,不论该函数体有多么小。

//这条建议一般不适用于类模板。

1.4

头文件能加强类型安全检查。如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担。

//在使用合理的情况下,这基本上是正确的,但头文件可以导致其它方面——像重构(典型情况如重命名一个函数)的复杂化。

第2章 程序的版式
这章基本是主观内容。读者需要注意风格是有争议的,其中的“良好风格”或“不良风格”并非公认。

2.8
很多C++教课书受到Biarne Stroustrup第一本著作的影响,不知不觉地采用了“以数据为中心”的书写方式,并不见得有多少道理。

我建议读者采用“以行为为中心”的书写方式,即首先考虑类应该提供什么样的函数。这是很多人的经验——“这样做不仅让自己在设计类时思路清晰,而且方便别人阅读。因为用户最关心的是接口,谁愿意先看到一堆私有数据成员!”

//“ Biarne Stroustrup ”拼写错误。C++之父的名字是 Bjarne Stroustrup 。有些一厢情愿了: C++ 的类定义中既然允许显式地表示 private 成员,就不是纯粹的接口描述方式。以我个人的经验,数据成员写在后面可能会导致顺序阅读代码时需要回溯。当类定义长度较小时这点影响不大,但定义长度比较长的时候(例如Loki::Functor里的代码)就会需要较频繁地滚屏,影响代码阅读效率。

第3章 命名规则
这章也基本是主观内容。

3.1
规则3-1-1

标识符应当直观且可以拼读,可望文知意,不必进行“解码”。

//这点和此文建议使用的匈牙利命名法有一定程度的矛盾。

规则3-1-3

命名规则尽量与所采用的操作系统或开发工具的风格保持一致。

//尽管大部分人应该乐于支持这个观点,不过事实上有时候无法实现。例如同时使用标准库和Windows API 风格的代码。这时倒不妨直接约定允许根据上下文选择要使用的命名风格。要点是,应该让人看出某个名称是用哪个风格命名的,而不至于一眼就混淆来源。

3.2
规则3-2-7

为了防止某一软件库中的一些标识符和其它软件库中的冲突,可以为各种标识符加上能反映软件性质的前缀。例如三维图形标准OpenGL的所有库函数均以gl开头,所有常量(或宏定义)均以GL开头。

//在 C++ 中应该考虑是否可以用命名空间代替前缀。

第4章 表达式和基本语句

我真的发觉很多程序员用隐含错误的方式写表达式和基本语句,我自己也犯过类似的错误。

//作者似乎没搞清楚“错误”一词的语义。

4.3
规则4-3-4
不要写成
        if (p== 0)  // 容易让人误解p是整型变量
        if (p!= 0)

//事实上,C++中的NULL典型地就是 int 字面量 0 (考虑到成文时间,不提新标准的空指针类型),和 int 兼容。以 Bjarne Stroustrup 的观点,这样恰恰会使人误以为 NULL 不是整数,因此推荐用 0 而不是 NULL 。

4.3.5

或者改写成更加简练的return (condition ? x : y);

//这里的括号是多余的。

4.4
这节不是语言本身而是涉及语言实现的内容。以现在的观点来看,优化器会可能会在此做一些工作。当然了解一些相关原理大体上还是有益的。

第5章 常量

常量是一种标识符,它的值在运行期间恒定不变。C语言用 #define来定义常量(称为宏常量)。C++ 语言除了 #define外还可以用const来定义常量(称为const常量)。

//谭XX风格的信口开河。这段引文中逗号或者句号之间的内容,没一个能算得上是正确的。

5.2
规则5-2-1

在C++程序中只使用 const常量而不使用宏常量,即const常量完全取代宏常量。

//这是有问题的。事实上很多情况下 const 只能让编译器被修饰的对象当做只读变量,而非编译期的真正意义的常量进行处理。与 #define 的符号常量(字面量)相比,只读变量受到了一些限制,例如不能作 case 的标号。

第6章 函数设计

C语言中,函数的参数和返回值的传递方式有两种:值传递(pass by value)和指针传递(pass by pointer)。

//错误。形式上, C 语言函数参数只按值传递。所谓的指针传递是按值传递的一种,只是传递参数的类型是指针而已。

6.1
规则6-1-1

参数的书写要完整,不要贪图省事只写参数的类型而省略参数名字。如果函数没有参数,则用void填充。

//不妥当。有时候参数的名称并非有意义,像 int max(int, int); 之类的原型,写了也不会让函数的意义更清楚。此外,并没有指出C函数没有参数时参数列表为 void ,这和省略参数列表(接受任意参数)是不同的。而 C++ 中省略参数列表和 void 参数相同,参数列表 ... 接受不确定个数的参数。

6.2
规则6-2-3

不要将正常值和错误标志混在一起返回。正常值用输出参数获得,而错误标志用return语句返回。

//在C++中可以不使用此规则而使用异常(在 C 中理论上也可以类似地使用 setjmp/longjmp ,但容易造成语义不明确,实际上基本不用)。

6.3
规则6-3-1

在函数体的“入口处”,对参数的有效性进行检查。

//在函数接口语义明确的情况下并非是必需的。例如 C 标准库 <string.h> 中以及 POSIX 标准中的许多函数。

规则6-3-2

在函数体的“出口处”,对return语句的正确性和效率进行检查。

//同样不是必需的。此外检查可能损失效率。

//这里是误读。但原文关于“临时变量”的说法有误。

要搞清楚返回的究竟是“值”、“指针”还是“引用”。

//注意返回对象的语义,但是刻意区分“值”和“指针”是不必要的,严格上是错误的——它们根本就不是可以比较的一类概念。

建议6-4-2

函数体的规模要小,尽量控制在50行代码之内。

//尽管为数不多,有些特殊情况,如编译器的某些分析程序,是明显的反例。

第7章 内存管理
“640Kought to be enough for everybody

—Bill Gates 1981”

//和本章主题无关。

7.1

内存分配方式有三种

//有误。内存分配具体方式由实现决定,语言只限制存储类。

7.2
漏了重复释放内存的错误(这通常会引起程序崩溃)。
规则7-2-1

用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。

//对 C++ 而言是错误的。 ISO C++ 关于内存分配失败的默认行为是抛出 std::bad_alloc 异常。如果要使分配失败不抛出异常,使用 nothrow 版本,或者设置实现相关的编译选项。

规则7-2-5

用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。

//不一定必要。例如指针是自动变量,在退出所在的块作用域被自动释放时。

7.3.1

该语句企图修改常量字符串的内容而导致运行错误

//有误。 C 语言中字符串字面量(具有数组类型)未必是常量。当然还是应该避免修改字符串字面量,这是未定义行为。

7.9

为new和malloc设置异常处理函数。例如VisualC++可以用_set_new_hander函数为new设置用户自己定义的异常处理函数,也可以让malloc享用与new相同的异常处理函数。

//应该补充的是,标准库有 std::set_new_handler 。

第8章C++函数的高级特性

const与virtual机制仅用于类的成员函数。

//应该强调“非静态”成员函数,否则就是错误的。

(虽然似乎没有更多明显的错误,不过遗漏的地方一堆,坚决不吐槽……= =)

第9章 类的构造函数、析构函数与赋值函数
9.1

Stroustrup的命名方法既简单又合理:让构造函数、析构函数与类同名,由于析构函数的目的与构造函数的相反,就加前缀‘~’以示区别。

//错误。构造函数和析构函数是无名的(这个细节决定了一些语言特性的限制,例如不能 using 声明基类的构造函数),看起来名称和类名相同的调用方式其实是语法的限制。

非内部数据类型的成员对象应当采用第一种方式初始化,以获取更高的效率。

//效率在这里倒是次要的(很容易被编译器优化掉),重要的是语义。另外,初始化列表的一些行为是受到特殊限制的,例如基类子对象和成员的初始化顺序和异常。

9.7

(仍然不想吐槽漏掉swap&copy这样高效可靠的方法而在operator=实现里分配内存……)

第10章 类的继承与组合
首先标题有点问题。类可以继承,组合的应该是类的实例而非本身。

如果将对象比作房子,那么类就是房子的设计图纸。所以面向对象设计的重点是类的设计,而不是对象的设计。

//因果关系不成立。而且观点是有问题的,仅适于经典的 class-based OOD 。

10.2
规则10-2-1

若在逻辑上A是B的“一部分”(a partof),则不允许B从A派生,而是要用A和其它东西组合出B。

//错误。尽管一般组合能够胜任这项工作,但并非绝对。可以使用private继承完成相同的任务,并且提供覆盖成员函数的特性。这是组合无法完成的。

第11章 其它编程经验
11.1.3

如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员函数,编译器将指出错误

//错误漏了 mutable 修饰的成员这个特例。

建议11-3-8

避免编写技巧性很高代码。

//不应该逃避。技巧性高不意味着难以理解;即使难以理解,也可以通过注释弥补。当然,前提是技巧要使用得合理。

建议11-3-13

把编译器的选择项设置为最严格状态。

//有时候现实不允许,例如考虑已有代码的兼容性,需要配置时会带来额外的复杂性。

附录C :C++/C试题的答案与评分标准
标准答案示例:
const float EPSINON = 0.00001;

if ((x >= - EPSINON) && (x <= EPSINON)

//如果是“标准”的,为什么不用标准库的 <float.h>/<cfloat> 的FLT_EPSILON而自己重复发明轮子?

三、简答题(25分)

1、头文件中的ifndef/define/endif 干什么用?(5分)

答:防止该头文件被重复引用。

//错误。条件编译显然不只用于给头文件增加 header guard 。

四、有关内存的思考题(每小题5分,共20分)
答:程序崩溃。
因为GetMemory并不能传递动态内存,
Test函数中的 str一直都是 NULL。

strcpy(str, "hello world");将使程序崩溃。

//错误。未定义行为不等同于程序崩溃,尽管很可能是这样。

六、编写类String的构造函数、析构函数和赋值函数(25分)

String& String::operate =(const String &other)

//关键字operator拼写错误。实现冗余就不说了。

EOF

《高质量C++/C编程指南》陷阱 【转】的更多相关文章

  1. 高质量C++/C编程指南(林锐)

    推荐-高质量C++/C编程指南(林锐) 版本/状态 作者 参与者 起止日期 备注 V 0.9 草稿文件 林锐   2001-7-1至 2001-7-18 林锐起草 V 1.0 正式文件 林锐   20 ...

  2. 学习笔记之高质量C++/C编程指南

    高质量C++/C编程指南 http://man.lupaworld.com/content/develop/c&c++/c/c.htm 高质量C++/C编程指南(附录 C :C++/C 试题的 ...

  3. 随笔 高质量 C++/C 编程指南

    内存分配方式有三种:) 从静态存储区域分配.内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量, static 变量.) 在栈上创建.在执行函数时,函数内局部变量的存储 ...

  4. 高质量c c++编程

    第1章 文件结构 每一个C++/C程序通常分为两个文件.一个文件用于保存程序的声明(declaration),称为头文件.还有一个文件用于保存程序的实现(implementation),称为定义(de ...

  5. 高质量C++[转]

    高质量C++/C编程指南 文件状态 [  ] 草稿文件 [√] 正式文件 [  ] 更改正式文件 文件标识: 当前版本: 1.0 作    者: 林锐 博士 完成日期: 2001年7月24日 版 本  ...

  6. C++/C高质量编程指南-笔记

    复习: C/C++高质量编程指南: [规则1-2-1]为了防止头文件被重复引用,应当用ifndef/define/endif结构产生预处理块. [规则1-2-2]用 #include <file ...

  7. c++高质量编程手册

    怡化主管强烈要求我读这本书.... 笔记尚未完成,持续更新呗.. 第1章 高质量软件开发之道 1.1 软件质量基本概念 1.1.1 如何理解软件的质量:功能性和非公能性 1.1.2 提高软件质量的基本 ...

  8. [转]C语言SOCKET编程指南

    1.介绍 Socket编程让你沮丧吗?从man pages中很难得到有用的信息吗?你想跟上时代去编Internet相关的程序,但是为你在调用 connect() 前的bind() 的结构而不知所措?等 ...

  9. C语言SOCKET编程指南

    1.介绍 Socket 编程让你沮丧吗?从man pages中很难得到有用的信息吗?你想跟上时代去编Internet相关的程序,但是为你在调用 connect() 前的bind() 的结构而不知所措? ...

随机推荐

  1. iterm2

    Mac下配置iterm2 http://www.dreamxu.com/mac-terminal/ 快捷键 http://cnbin.github.io/blog/2015/06/20/iterm2- ...

  2. 在Android项目中引入MuPdf

    由于公司手机App要加入一个附件查看功能,需要查看PDF文件,在网上找了许多第三方工具,最后选择了MuPDF. 更多第三方工具可以查看大神总结的:http://www.cnblogs.com/poke ...

  3. snr ber Eb/N0之间的区别与联系

    信噪比(S/N)是指传输信号的平均功率与加性噪声的平均功率之比,载噪比(C/N)指已经调制的信号的平均功率与加性噪声的平均功率之比,它们都以对数的方式来计算,单位为dB. 对同一个传输系统而言,载噪比 ...

  4. Java创建Web项目

    首先下载Tomcat服务,用来运行JAVA程序,跟windows中的IIS类似 下载地址:tomcat.apache.org ,最好下载ZIP压缩版的,解压后就可以直接用.如下图: 检查Tomcat是 ...

  5. CodeForces 711A Bus to Udayland (水题)

    题意:给定一个n*4的矩阵,然后O表示空座位,X表示已经有人了,问你是不能找到一对相邻的座位,都是空的,并且前两个是一对,后两个是一对. 析:直接暴力找就行. 代码如下: #pragma commen ...

  6. C++ Primer学习_第1章

    源文件后缀 在大多数的系统中,源文件的名字以一个后缀为结尾,后缀是由一个句点后接一个或多个字符组成的.后缀告诉系统这个文件是一个C++程序.不同编译器使用不同的后缀命名约定,最常见的包括.cc..cx ...

  7. C#微信开发之旅--基本信息的回复

    上一篇说到配置和验证<C#微信开发之旅--准备阶段> 下面来实现一下简单的信息回复. 也就是接收XML,返回XML 可以去看下微信开发文档的说明:http://mp.weixin.qq.c ...

  8. CycleScrollView实现轮播图

    // //  CycleScrollView.h //  PagedScrollView // //  Created by 李洪强 on 16-1-23. //  Copyright (c) 201 ...

  9. Android(java)学习笔记183:判断SD卡状态和存储空间大小

    当我们在使用SD卡时候,如果我们想往SD卡里读写数据,我们必须在这之前进行一个逻辑判断,那就是判断SD卡状态和SD存储空间大小: 核心代码: String status = Environment.g ...

  10. Unity3D 5.0简单的射线检测实现跳跃功能

    这里是一个简单的跳跃,5.0和其他版本貌似不一样,并且,再起跳功能做的不完全. 不过一个基本的思路在这里. 1.首先,射线检测,这里是利用一个空对象,放到主角对象的下面 2.然后调节射线的位置,在主角 ...