随笔 - 10, 文章 - 0, 评论 - 34, 引用 - 0

[原][译] Tips for Better Coding Style --- 关于更好的编程风格的建议

[C/C++] - Tips for Better Coding Style

关于更好的编程风格的建议 (v1.5)

Translated By Phoenix(phoenix8848@gmail.com)

    In this entry, I show you 4 tips that address frequently asked questions from C++ programmers of all levels of expertise. It's surprising to discover how many experienced programmers are still unaware of the deprecation of the .h notation of standard header files, the proper usage of namespaces, and the rules regarding binding of references to temporary objects, for example. These issues and others will be discussed here.

    First, we start by explaining the difference between the deprecated “xxx.h” header names and the modern, standard-compliant “xxx” header-naming notation. Next, we explore a few dark corners of C++ which due to compilers' limitations and the somewhat recondite nature of the associated language rules tend(原文为“rulestend”) to confuse many programmers, e.g., the notion of comma-separated expressions and the rules of binding references to rvalues. Finally, we will learn how to invoke a function prior to a program's startup.


    Tip 1: “iostream.h” or “iostream”?

    语题1:“iostream.h” or “iostream”?

    Many C++ programmers still use “iostream.h” instead of the newer, standard compliant “iostream” library. What are the differences between the two? First, the .h notation of standard header files was deprecated more than five years ago. Using deprecated features in new code is never a good idea. In terms of functionality, “iostream” contains a set of templatized I/O classes which support both narrow and wide characters, as opposed to “iostream.h” which only supports char-oriented streams. Third, the C++ standard specification of iostream's interface was changed in many subtle aspects. Consequently, the interfaces and implementation of “iostream” differ from those of “iostream.h”. Finally, “iostream” components are declared in namespace std whereas “iostream.h” components are global.

     很多C++程序员还在使用“iostream.h”代替新的符合标准的“iostream”库。两者有什么区别呢?首先,标准头文件“.h”扩展名在五年前就倍受争议。在新代码中使用有争议的(过时的)特性永远都不是一个好主意。从本质上看,“iostream”包括一系列支持窄字符与宽字符的模板化(templatized) I/O输入输出类,而相反地,“iostream.h”只支持字符流。第三,iostream接口的标准C++规范在许多细节方面进行了变动。因此,“iostream”的接口与实现同那些“iostream.h”是有区别的。最后,“iostream”是在std命名空间中定义的而“iostream.h”则是全局的。

    Because of these substantial differences, you cannot mix the two libraries in one program. As a rule, use “iostream” unless you're dealing with legacy code that is only compatible with “iostream.h”.


    Tip 2: Binding a Reference to an R-Value



    R-Values and L-Values are a fundamental concept of C++ programming. In essence, an R-Value is an expression that cannot appear on the left-hand side of an assignment expression. By contrast, an L-Value refers to an object (in its wider sense), or a chunk of memory, to which you can write a value. References can be bound to both R-Values and L-Values. However, due to the language's restrictions regarding R-Values, you have to be aware of the restrictions on binding references to R-Values, too.


    Binding a reference to an R-Value is allowed as long as the reference is bound to a const type. The rationale behind this rule is straightforward: you can't change an R-Value, and only a reference to const ensures that the program doesn't modify an R-Value through its reference. In the following example, the function f() takes a reference to const int:

    将引用与右值绑定像引用常量(这里const type应为"常量",感谢新奥尔良土鳖 )一样也是被允许的。这条原则背后的原理是很显而易见的:你无法改变右值,因为对常量的引用确保程序不会通过这个接口改变右值。下面的例子,f()函数包含一个对整型变量的引用。

1 void f(const int & i);
3 int main()
4 {
5 f(2); /* OK */
6 }

    The program passes the R-Value 2 as an argument to f(). At runtime, C++ creates a temporary object of type int with the value 2 and binds it to the reference i. The temporary and its reference exist from the moment f() is invoked until it returns; they are destroyed immediately afterwards. Note that had we declared the reference i without the const qualifier, the function f() could have modified its argument, thereby causing undefined behavior. For this reason, you may only bind references to const objects.

    这段代码将右值“2”做为函数f()的一个参数。代码运行时,C++将创建一个值为2的临时整型变量并将其与引用类型i绑定。这个临时对象与它的接口将在 f()运行期间一直存到直到函数f返回。函数f返回后它们立即被释放。注意我们没有将i声明为常量类型,但是函数f仍有可能修改它的这个参数,这将引起异常。因此最好是将引用与常量类型绑定。

    The same rule applies to user-defined objects. You may bind a reference to a temporary object only if it's const:


struct A{};

1 void f(const A& a);
3 int main()
4 {
5     f(A()); /* OK, binding a temporary A to a const reference*/
6 }

    Tip 3: Comma-Separated Expressions


Comma-separated expressions were inherited from C. It's likely that you use such expressions in for- and while-loops rather often. Yet, the language rules in this regard are far from being intuitive. First, let's see what a comma separated expression is.


    An expression may consist of one or more sub-expressions separated by commas. For example:


1     if(++x, --y, cin.good()) /*three expressions*/

The if condition contains three expressions separated by commas. C++ ensures that each of the expressions is evaluated and its side effects take place. However, the value of an entire comma-separated expression is only the result of the rightmost expression. Therefore, the if condition above evaluates as true only if cin.good() returns true. Here's another example of a comma expression:


1 int j=10;
2 int i=0;
4 while++i, --j)
5 {
6     /*..repeat as long as j is not 0*/
7 }

    Tip 4: Calling a Function Before Program's Startup


Certain applications need to invoke startup functions that run before the main program starts. For example, polling, billing, and logger functions must be invoked before the actual program begins. The easiest way to achieve this is by calling these functions from a constructor of a global object. Because global objects are conceptually constructed before the program's outset, these functions will run before main() starts. For example:


 1 class Logger
 2 {
 3 public:
 4     Logger()
 5     {
 6         activate_log();
 7     }
 8 };
10 Logger log; /*global instance*/
12 int main()
13 {
14     record * prec=read_log();
15     //.. application code
16 }

    The global object log is constructed before main() starts. During its construction, log invokes the function activate_log(). Thus, when main() starts, it can read data from the log file.


posted on 2008-09-15 23:13 西门有悔 阅读(2161) 评论(12)  编辑 收藏 引用


# re: [原][译]关于更好的编程风格的建议  回复  更多评论   

2008-09-16 00:14 | abettor

# re: [原][译]关于更好的编程风格的建议  回复  更多评论   




2008-09-16 01:42 | 西门有悔

# re: [原][译]关于更好的编程风格的建议  回复  更多评论   

As a rule, use “iostream” unless you're dealing with legacy code that is only compatible with “iostream.h”.

2008-09-16 09:06 | autumnm1981

# re: [原][译]关于更好的编程风格的建议  回复  更多评论   

2008-09-16 10:02 | 新奥尔良土鳖

# re: [原][译]关于更好的编程风格的建议  回复  更多评论   

2008-09-16 11:52 | 肥仔

# re: [原][译]关于更好的编程风格的建议[未登录]  回复  更多评论   

2008-09-16 13:05 | 陈梓瀚(vczh)

# re: [原][译]关于更好的编程风格的建议  回复  更多评论   


2008-09-16 15:52 | 西门有悔

# re: [原][译]关于更好的编程风格的建议  回复  更多评论   



2008-09-16 15:53 | 西门有悔

# re: [原][译]关于更好的编程风格的建议  回复  更多评论   


2008-09-16 15:55 | 西门有悔

# re: [原][译] Tips for Better Coding Style --- 关于更好的编程风格的建议[未登录]  回复  更多评论   

2008-09-17 13:10 | 陈梓瀚(vczh)

# re: [原][译] Tips for Better Coding Style --- 关于更好的编程风格的建议  回复  更多评论   

Thx to your great sharing!
2008-09-18 00:40 | Kven

# re: [原][译] Tips for Better Coding Style --- 关于更好的编程风格的建议  回复  更多评论   

The same rule applies to user-defined objects. You may bind a reference to a temporary object only if it's const:


这里的"only if it's const"感觉应该是修饰"reference",即翻译为“只有当引用为const时才可以将其绑定到一个临时对象”,《C++编程思想》上好像也提到了这点,不知道是不是我理解有误。
2009-07-22 10:01 | k.j

【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理