欢迎来到天天文库
浏览记录
ID:38525642
大小:32.56 KB
页数:14页
时间:2019-06-14
《移植Java代码到C++的技巧二》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、移植Java代码到C++的技巧二二、字符串对象(stringvsString): 在Java的代码中,我们经常会看到这样一种写法,相信几乎每一个Java程序员都有过这样的代码,因此他看上去非常熟悉,甚至还带有一点儿亲切感。1publicStringgetName(){2returnname;3} 这样的代码在Java中确实司空见惯,也无可厚非,因此对于我们来说没有太多可以讨论的空间,除非你非常希望了解JVM中对象常量池的概念,然而它并不是我们这个条目中将要讨论的主题。 那么现在让我们来看一下在C++中又是如何处理此类问题的,下面将列举出三种最常用的实现方式。 方
2、法一:直接返回内部name成员的指针。1constchar*getName(){2return_name;//_name变量的类型为char*3} 方法二:基于成员变量name的数据,重新分配相同长度的内存空间,之后再将name中的数据copy过来,最后返回函数中新分配的地址。1char*getName(){2size_tlength=strlen(_name);3char*result=malloc(length+1);4assert(result);5memcpy(result,_name,length);6result[length]=' ';7returnresult;
3、8} 方法三:基于成员变量name的数据,返回C++标准库中的string对象。1stringgetName(){2return_name;//这里_name成员变量的类型不是char*,而是string。3} 首先需要肯定的是以上三种方法在一定程度上均能满足我们的需求,但也都存在各自的不足。现在我们需要针对以上三种实现逐一给出我们的剖析。 1.直接返回内部数据的指针,这本身就是一个疯狂而又极度危险的实现方式。因为对于函数调用者而言,可以随时通过返回的指针修改其所指向的数据,从而破坏了该函数所在对象的数据封装性。事实上,我们在自行编写C++代码时,也是很少这样设计和
4、实现此类函数的。 2.和第一种方法相比,在同样实现功能的基础上,确实避免了内部数据会被调用者修改的风险,然而这样的做法却带来了效率开销,而且还从另外一个方面破坏了该函数所在类的封装性。 先说效率问题,很明显该方法和方法一相比多了一次内存分配和内存拷贝的操作,而此操作对性能的影响程度也需要视情况而定。至于封装性被破坏的问题其实也是非常明显的,因为返回值中的数据指针是在该函数内部被临时分配的,是需要被调用者自行释放的,因此对于调用者来说就需要关注该函数的内存分配方式,如果是malloc,调用者就需要使用对应的free函数来释放该内存空间,如果是new,则需要用delete[]的方式
5、来释放。一旦分配和释放内存的方式不匹配,将会导致极为严重而又难以察觉的堆内存混乱问题。直接引发的后果就是程序在运行时极不稳定,随时都有崩溃的可能,而开发人员在定位此类问题时也是非常非常的困难,因为通常他们报错的方式比较随机。有经验的开发者可以通过内存检测工具来帮助他们实现问题定位,然而在他们决定使用工具之前,则需要通过大量的其他手段来分析和判断该问题可能是内存混乱所致。可以想象,这样一个微小的失误,给程序后期的调试和维护所带来的压力是难以估量的。这里还需要额外指出的是,如果该函数(getName)和调用函数分属不同的动态库,那么对于调用者而言,即便内存释放的方式和分配时保持一致,仍然有可能
6、导致内存混乱的问题发生。至于具体原因,我们会在后面的条目中给出更为清晰的示例和解释。 3.和第一种方法相比,该方式也存在着同样的效率问题。 由于该函数返回的是string对象本身,而不是对象的指针或引用,因此在函数返回时,将产生一次拷贝构造,用来生成并初始化返回的string对象。在该拷贝构造中,内存重新分配和内存数据拷贝等指令均将会被执行。然而需要指出的是,和前两种方法相比,该方法避免了对象封装性被破坏和可能造成的堆内存混乱等问题的发生,从而更好的保证了程序在运行时的稳定性。 需要另行指出的是,在实际开发中的绝大多数情况下,调用者针对此类函数返回的字符串都仅仅是执行读
7、操作,如数据比较、数据打印或直接插入数据库等。只有在极个别的时候才会去主动修改它,因此额外的内存分配和拷贝操作所带来的开销往往是另人沮丧的。 在经过对上述三种方法的深入分析之后我们得出结论,为了更好和更彻底的解决字符串对象相关代码的移植问题,我们将不得不另辟蹊径,以找出运行效率较高、代码移植成本最低的方式。下面将给出我在实际移植Java代码到C++代码的过程中所采用的方法,见如下代码片段:1StringgetNam
此文档下载收益归作者所有