i++ 引发的惨案

栏目: C++ · 发布时间: 7年前

内容简介:最近在做一个项目,该项目原来是由C++编写的,现在需要翻译成Java,在翻译过程中,同事没有理解清楚具体需求,在开发中进行了直译,直到生产上出现故障了(测试居然没测出来?)一起研究才发现...先看一下C++代码的样子然后看一下同事翻译的第一版的样子

最近在做一个项目,该项目原来是由C++编写的,现在需要翻译成Java,在翻译过程中,同事没有理解清楚具体需求,在开发中进行了直译,直到生产上出现故障了(测试居然没测出来?)一起研究才发现...

需求

先看一下C++代码的样子

//vector<CorBillGroup>& vCorBillGroups 
	while(rs->next()){
		if(load(rs,bill)){
			//判断分组
			corId = pm->getCorpId(bill.getPartyRoleId(),bill.getBillingCycleId());
			if (corId < 0)
				throw BusinessLogicException("找不到银行划扣分组ID", corId);
			int i=0;
			for ( i=0;i<vCorBillGroups.size();i++) {
				 if(vCorBillGroups[i].getCorperationId() == corId){
					 vCorBillGroups[i].add(bill);
					 break;
				 }
			}
			if(i == vCorBillGroups.size()) {
				CorBillGroup corBillGroup;
				corBillGroup.setCorperationId(corId);
				corBillGroup.add(bill);
				vCorBillGroups.push_back(corBillGroup);
			}
		}
	}
复制代码

然后看一下同事翻译的第一版的样子

for (VirtualBillVO vo : bills) {
            long partyRoleId = vo.getPartyRoleId();
            Partner partner = getPartnerManager().getPartner(Integer.parseInt(partyRoleId + ""));
            corId = partner.getCorpId();

            if (corId < 0) {
                throw new BusinessLogicException("找不到银行划扣分组ID", corId);
            }
            int i = 0;
            for (CorBillGroupVO corVo : vCorBillGroups) {
                i++;
                if (corVo.getM_iCorperationId() == corId) {
                    corVo.add(vo);
                    break;
                }
            }
            if (i == vCorBillGroups.size()) {
                CorBillGroupVO corBillGroup = new CorBillGroupVO();
                corBillGroup.setM_iCorperationId(corId);
                corBillGroup.add(vo);
                vCorBillGroups.add(corBillGroup);
            }
        }
复制代码

分析

先不考虑这里具体是干啥的,单纯从代码结构的角度来看,似乎代码是没啥问题的。但是程序可不是看代码结构的! 由于C++代码有具体业务含义,简单介绍一下这段代码的背景:给一组账单(bills),按照运营商(corId)进行分组后返回。这么简单的需求,也不知道C++代码为啥写的这么复杂,这也导致翻译这段代码的同事犯了糊涂。

  • 具体看C++: 循环账单列表,取账单的corId,i=0.循环分组vCorBillGroups,若分组里有该corId就将该账单添加到vCorBillGroups的第i个元素中,并跳出循环,判断i 和vCorBillGroups长度是否相等,若在前面循环中有break,i是不可能与vCorBillGroups的长度相等的(循环vCorBillGroups.size()次,每次i++,则当循环正常结束后,i肯定与vCorBillGroups.size()相等,若有break,则i肯定小于i肯定与vCorBillGroups.size()了);若前面循环中没有break,说明该corId不在已经存在的组中,则添加到vCorBillGroups中。
  • 再看同事翻译的Java:同样循环账单列表,但是采用了foreach的写法遍历,break条件满足之前就i++,那么在无break的时候是正常的,在有break的情况下就不一样了,例如vCorBillGroups.size() = 1 时,遍历一次vCorBillGroups,此时就算有break,i = 1,i ==vCorBillGroups.size();又会重新添加一次分组,那么就与C++代码的含义不一样了。
  • 区别在哪里呢,仔细对比一下就会发现,两处代码的区别就在i++的使用上,for(;;i++)中,若for循环中有break,是不会进行++操作的,同事翻译时为了图方便,随意使用foreach,并将i++置于break条件之前,很明显无法起到控制作用了!

解决

最简单的解决方式就是如上述分析一样,将i++放在break条件之后即可,但是分组代码真的要写这么晦涩吗?见仁见智了...

总结

很少有人真的去注意i++和++i的区别,我老大在看到这段代码的时候也犹豫了一下,后来才恍然大悟怀疑这个i++在break之后是否有执行,测试了一下才确定自己的想法。平时这种代码可能都是不会有问题的,但是一旦触发了某种边界条件,就不一定是你想象的样子了。所以在写代码之前,还是要明确自己要实现的功能是什么,如果同事最开始翻译代码的时候明确知道这是一段分组代码,我相信他绝对不会这样去写的!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Joy of X

The Joy of X

Niall Mansfield / UIT Cambridge Ltd. / 2010-7-1 / USD 14.95

Aimed at those new to the system seeking an overall understanding first, and written in a clear, uncomplicated style, this reprint of the much-cited 1993 classic describes the standard windowing syste......一起来看看 《The Joy of X》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具