[声明]:本英文资料源自于Herb Sutter 创建的“Conversation”栏目,“C++ 翻译小组”的翻译作品供学习交流与参考用途,不得用于任何商业用途。未经Herb Sutter、Jim Hyslop同意,不得转载;对于违反以上条款,翻译小组对此不负任何责任;特此声明。
文章来源:http://www.gotw.ca
版权归属:Herb Sutter and Jim Hyslop
译 者:徐波
对话#04: 谁的代码更易于移植? [1]
“嗨!伙伴。”珍妮过来坐在我对面,周围一片狼藉,“还有别的传闻吗?”
我看了看时间,只是想搞清楚确切时间。但我不想再逗留半个时。于是叫道:“嗨,伙计,没有了。他们不管三七二十一,在上面加了个盖,你下班这么早吗?”
“布拉森科沃斯基睡不着,所以我就解脱了。我下次补他。”
“他很有想法,”我嘴里又塞了一口饭,同意道,“我真是欣赏他。他总是干得很好,确保不会影响其它人。知道他自己在整个队伍里的位置。我希望在下个月在行星上着陆后还能跟他一块工作。每个人都应该象他这样敬业。”
“大多数人都是这样的,”珍妮微笑道,“你自己也不懒啊。”
“事实上,”我哈哈大笑,“这使我想起了鲍勃。对了,我已经跟你说起过他,他是我第一次工作中碰到的另一个怪人。有时候他的所作所为真让人想把他耳垂拧下来。说到点子上,当一个人做事一声不吭时我们就会说他在“拔活”你明白这个意思吗?
我继续解释......
- - - - - - - - - - - - - - - - - - - - - - - - -
我身后的一个声音说道:“嗨,新来的,你破坏了整体结构。”
我暗暗叹息了一声,闭起眼睛。我工作已经快两个月了,这个该死的程序员鲍勃对我傲慢的称呼,尤其是这声“新来的”,简单比Guru叫我“徒弟”更令我憎恨。我数到十,然后头也不回地回答:“你说什么啊,鲍勃?”
“你最近的那些代码,”鲍勃和气地回答,呷了一口咖啡。“我的编译器在编译这些代码时有点问题,它抱怨说一个iterator已经被定义。你破坏了结构,最好在她发现前改正。”我有点吃不准,毕竟我还是个新手,我明白破坏整体结构不是件好事。我可以想象Guru的反应:记住,徒弟,团队合作的第二准则:你不能破坏整体结构。
“OK,好的,”我又叹了口气,这次发出了声音,“你说的是哪段代码?”
鲍勃探身过来,按了几个键,拉出一个函数,看上去是这样的:
// OBJMAP is a typedef for a standard container
void f( OBJMAP &theMap )
{
for( OBJMAP::iterator iter = theMap.begin();
iter != theMap.end();
++iter ) {
// do something
}
// other code in here
for( OBJMAP::iterator iter = theMap.begin();
iter != theMap.end();
++iter ) {
// do something else
}
}
“有什么问题吗?”我问道,“我仔细看过Stroustrup的书,iterator在每个循环结束后应该失效。”
“对,是这样,可在我的编译器上不是这样。”鲍勃答道,挖了挖牙齿,“它抱怨说iter已经被定义。很容易修正吧,虽然...只要去掉iter的第二个声明。事实上,我接手时,原先的代码就是这样的。然后你出现了,并破坏了整体结构。”
这下我明白了。不过,由于我尚处于试用期,所以语气比较委婉。“鲍勃,”我耐心说理,“这在我们所有的目标平台上都能通过编译。我加上第二个声明是因为我的编译器抱怨说第二个iterator未被定义,应该象我那样做才行,Stroustrup的书上也是这样说的。”
鲍勃看上去有点不耐烦:“我并不关心你的新式编译器。我那个编译器已经用了好几年了,它从没让我失望过。你的代码无法工作。”
“鲍勃,代码没问题。它在我的编译器里工作得很好。”
“那是你的编译器有问题。这不是我的错。我干我自己的活,我并不关心其它编译器。”鲍勃再次耸耸肩,语气中戒备心理更重。
一个轻轻的声音在我们身后响起:“我觉得你有几丝惧意。”
我微微一震,鲍勃更吃惊,他的咖啡洒出了一些。Guru还在老远,正静静地向我们走来,跟往常一样,手里捧本大书。
Guru轻轻地摇了摇她那长了一头灰发的头,皱了皱眉,“害怕导致恼火,”她继续说道。
“啊,停。我才不怕其它编译器呢!”鲍勃激动地嚷道,舔了舔洒了手腕上的咖啡,“我才不理会它们呢。”
“恼火导致憎恨。憎恨...导致磨难。”
“是啊,我正受折磨呢。”我暗暗自语,“我只是想编写可移植的代码。对了,鲍勃,”我让步道,只想摆脱他的纠缠,“我会修改的,能让它工作,可以了吧?”
“象我说的那样,新来的,去掉第二个声明。”他再次大声说道,然后转身离去。
温迪从隔壁小屋出来,看着他离去。“鲍勃这次在抱怨些什么?”她问我们。Guru站在附近,继续读那本大书。我向温迪展示了那段代码,并解释了一下鲍勃想做什么。“他就是这样,”温迪嗤了嗤鼻,“让他选择实现一个可移植的方案或者最适合他自己的编译器的方案,他总是选择后者。就象你说的,他的代码无法移植。对了,现在这个情况,你不必在每个循环处声明一个新的iterator。只要在第一个循环前声明一次,这样在所有的编译器里都能工作了。”她快速地在代码中作了一些修改:
// OBJMAP is a typedef for a standard container
void f(OBJMAP &theMap)
{
OBJMAP::iterator iter;
for( iter = theMap.begin();
iter != theMap.end();
++iter ) {
// do something
}
// other code in here
for( iter = theMap.begin();
iter != theMap.end();
++iter ) {
// do something else
}
}
Guru抬起头,看了看这个解决方案。“很好,小姐。”温迪扬了扬眉,但只是微微的,她已经习惯了。“而且,正象你所提示的,这并不是唯一的解决方案。另一种更优雅的方案是完全避免iterator声明,而且可能看上去更清楚,就是用for_each和表达式模板(expression template),只要有可能,就应该使用它们,徒弟。”Guru继续对我说,“重要的是要知道、理解并遵守神圣的标准,同样重要的是要熟悉自己的工具,即使有点离经叛道。鲍勃使用的编译器不支持在for语句初始式中声明变量。只要他还用他那个编译器,就没法照顾可移植代码。”
“嗯...”我说道,擦了擦下巴,“编写可移植代码比我想象的要困难。所以我们不得不等鲍勃的编译器的新版本出来,才能使用我原先所写的代码。”
Guru将目光投向远处,过了一会说道:“我不是先知,无法预见将来。然而,我是这样设想的:可移植性问题永远不会真正消失。编译器不会全部合丝合缝地符合标准。有些厂商甚至可能在它们的编译器里留有淘汰了的东西,目的是不破坏以前遗留的代码。”
“同时,有些编译器将引入标准之外的新特性,在其内部或与其相关,这很好,否则这门语言会变得陈腐、不灵活,最终死于停滞。只基于该平台的程序可能会受益于该特性。在需要移植的代码中使用这些非标准的特性会不会带来灾难?有些新手,象你这样,可能会不经意地使用它们,而不曾注意到它们是无法移植的。不要太沉湎于某种编译器,以致害怕其它的编译器。害怕会导致不可移植。”
她停了一下,接着转身离去。我们听到她你仍在说道:“我希望我能想起那个说过‘理论和实践的区别实际上要比在理论上更大一些...’这句话的智者的名字。”
- - - - - - - - - - - - - - - - - - - - - - - - -
“鲍勃可算不上个大人物,”我总结道。
“没人把鲍勃跟加尼米德联系在一起,”珍妮同意道,“没太多可原谅之处,只是一些。嗨,你得走了,安德森在等你呢。”
我看了看时间,站了起来:“上班了。第三轮值班后你和劳拉在干什么?”我问道,我发现较之谈论鲍勃,甚至是Guru,还有些事情谈论起来更有趣。
[注释]
[1] To the tune of "For He's a Jolly Good Fellow."
[2] Bjarne Stroustrup. The C++ Programming Language, 3rd Edition (Addison-Wesley, 1997).
[3] See the feature article on expression templates in the May 2000 issue of C++ Report.
[关于作者]
Herb Sutter
是个独立顾问,也是ISO/ANSI C++标准委员会的秘书。你可通过hsutter@acm.org.联系他
Jim Hyslop
Leitch Technology International Inc.资深的软件设计师,你可通过jim.hyslop@leitch.com联系他