2、在Java中,TreeMap的参数类型必须为对象类型,不能为原始数据类型,如int、double等,否则编译器将报编译错误。而在C++中,对模参的类型则没有此类限制。如果当Java源代码中TreeMap的值参数类型为自定义对象时,那么在C++中与其对应的值模参类型很有可能为该自定义对象的指针类型,否则将只能是该对象类型本身,这样在插入对象时,会有对象copy的动作发生,从而对性能造成一定的负面影响,通常而言,我们会选择使用该类的指针类型作为该容器的值模参类型。见如下Java代码:

public class MyTest {
         private int _value;
         public MyTest(int value) {
             _value = value;
         }
   
         public static void main(String[] args) {
             TreeMap<Integer,MyTest> tm = new TreeMap<Integer,MyTest>();
             tm.put(5, new MyTest(10));
             System.out.println("The count of the TreeMap is " + tm.size());
             Set<Entry<Integer,MyTest>> entries = tm.entrySet();
             Iterator<Entry<Integer,MyTest>> it = entries.iterator();
             while (it.hasNext()) {
                 Entry<Integer,MyTest> e = it.next();
                 System.out.printf("key = %d, value = %d ",e.getKey().intValue(),e.getValue()._value);
             }
         }
     }
     //The count of the TreeMap is 1
     //key = 5, value = 10

  以上为Java的完整代码和输出结果。如果我们仍然用该种方式完成C++的代码实现,这样正确吗?答案是输出结果是一致的,但是在C++代码中却存在着一个极为低级的失误。对,内存泄露。见如下C++代码及代码注释:

using namespace std;
     class MyTest
     {
     public:
         MyTest(int value) {
             _value = value;
         }
         ~MyTest() {}
     public:
         int getValue() const {
             return _value;
         }
     private:
         int _value;
     };
   
     int main()
     {
         map<int,MyTest*> m;
         m.insert(make_pair(5,new MyTest(10)));
         map<int,MyTest*>::iterator it = m.find(5);
         printf("The count of the map is %d. ",m.size());
         it = m.begin();
         for (; it != m.end(); ++it)
             printf("key = %d, value = %d ",(*it).first,(*it).second->getValue());
         return 0;
     }
     //The count of the map is 1
     //key = 5, value = 10

  在执行以上代码之后,如果借助于Valgrind(Linux gcc)或BoundChecker(Visual C++)等内存检测工具,便可以清楚的看到插入的MyTest对象指针在程序退出之前没有被正常释放,从而导致了内存泄露。见如下修订后的C++代码:

//该宏是我在实际项目中经常用到的工具宏之一
     #define RELEASE_MAP(Type1,Type2,variable)   
         do {
             map<Type1,Type2*>::iterator it = (variable).begin();
             for (; it != (variable).end(); ++it) 
                 delete (it->second);   
             (variable).clear();       
         } while(0)
           
     int main()
     {
         map<int,MyTest*> m;
         m.insert(make_pair(5,new MyTest(10)));
         map<int,MyTest*>::iterator it = m.find(5);
         printf("The count of the map is %d. ",m.size());
         it = m.begin();
         for (; it != m.end(); ++it)
             printf("key = %d, value = %d ",(*it).first,(*it).second->getValue());
         RELEASE_MAP(int,MyTest,m);
         return 0;
     }

  修订后代码的输出结果与之前的代码是完全相同的,只是容器中对象指针的内存泄露问题此得以解决。然而这种类似的内存资源管理问题给你带来的困扰,将会在整个代码移植的过程中贯穿始末。有的时候我甚至直接忽略了内存资源泄露问题,并将C++的代码写的和Java中的源码完全一致,直到某一时刻才突然惊醒的发现,之后是不得不沮丧的进行重构,按照C++的机制和习惯方式重新实现该部分逻辑。

  这里我们将不再此类问题做过多的赘述和解释,后面会有一个单独的条目来演示和分析该类问题。