Safe, Generic Programming

C++ Primer 4/e 在vector这里有一个关键概念:‘Programmers coming to C++ from C or Java might be surprised that our loop used != rather than < to test the index against the size of the vector. C programmers are probably also suprised that we call the size member in the for rather than calling it once before the loop and remembering its value.

C++ programmers tend to write loops using != in preference to < as a matter of habit. In this case, there is no particular reason to choose one operator or the other. We’ll understand the rationale for this habit once we cover generic programming in Part II.

Calling size rather than remembering its value is similarly unnecessary in this case but again reflects a good habit. In C++, data structures such as vector can grow dynamically. Our loop only reads elements; it does not add them. However, a loop could easily add new elements. If the loop did add elements, then testing a saved value of size would failour loop would not account for the newly added elements. Because a loop might add elements, we tend to write our loops to test the current size on each pass rather than store a copy of what the size was when we entered the loop.

As we’ll see in Chapter 7, in C++ functions can be declared to be inline. When it can do so, the compiler will expand the code for an inline function directly rather than actually making a function call. Tiny library functions such as size are almost surely defined to be inline, so we expect that there is little run-time cost in making this call on each trip through the loop.’

中文版的是这样说:‘C或Java程式员可能会对“在回圈内使用 != 而非 < 来测试索引值和vector大小”感到惊讶。C程式员可能也会对“在for内呼叫size()而非在回圈前呼叫一次并记住其值”感到惊讶。

C++程式员习惯上倾向使用 != 而较不喜欢使用 < 来写回圈。倒是没有特别理由一定要选用某个运算子。第Ⅱ篇谈到泛型编程(generic programming)后读者就会了解这个习惯的缘由。

“呼叫size()而非记住其值”在这里同样也非必要,但再次反映一个良好的习惯。在C++,vector这一类资料结构可以动态成长。虽然此处的回圈只读取元素,并没有增加元素,然而回圈内的确轻易可以加入元素。果真如此,那么测试前储存size就会出错,回圈将因此不处理新加入的元素。由于回圈可能加入元素,所以我们倾向每次测试当下的size,而非纪录进入的回圈前的size。

如同第7章即将看到,C++函式可宣告为inline。一旦如此,编译器会把inline函式的程式码当下展开,而非产生一个函式呼叫。小型函式如size()几乎肯定会被定义为inline,所以可预期“每个迭代都呼叫一次”只带来很小的执行期成本。’

用 != 真得很令人讶异,而且一般来说我会习惯使用记住size,除非这个阵列或物件的size真的向作者说会变大或减少时,我才不会用记住的方式。不过如果size是用inline的方式而且执行期成本是这么低的话,那变更习惯却是没什么不好。