su_junwei 发表于 2011-3-21 11:19:51

OpenFOAM瞬态对象模板类tmp的分析及其使用

今天讨论一下tmp的使用方法。讨论从下面三个方面进行展开 1)为什么要tmp;2)tmp工作原理;3)tmp怎么用;

1)为什么要tmp

   利用tmp主要是为了提高程序的执行效率,不是必须的。比如,我们定义一个有返回值的函数,当该函数被调用的时候,返回值会被复制给其他对象,然后函数内的返回值被释放;比如

   //定义函数

   label A()

   {

      label a = 10;

      return a; //返回局部变量a

   }

   调用函数;这时候函数A()内的局部变量a被复制,并赋给aa,函数结束a被释放;

   label aa = A();

   上面是一般函数调用机制,没有问题。如果a是一个占有非常大内存的对象,比如一个场量(100w个数据),这时候如果再复制a赋给aa会浪费很大计算机资源。这时候tmp就出现了;tmp就是让一个函数返回的时候,并不进行数据拷贝,从而提高效率。他是怎么实现这一点的呢?

2)tmp的工作原理

tmp的实现也不是很复杂;他主要程序设计的两种基本存储方式:堆存储和栈存储;堆存储时通过程序员指定的的存储,通过new或者malloc来完成,该存储空间需要程序员手动释放(通过delete或者free),否则这块空间永远保存在堆中。而栈是通过编译器自动申请空间和释放空间的,无需人为干预。他的实现就是通过在栈中声明一个指针指向堆空间,当函数返回时,给栈内的指针会自动复制给其他对象,并释放局部函数空间指针,这时,新的指针就会指向在堆中申请的空间的数据,避免大规模copy,实现效率的提高;他的实现和下面类似;

   scalarField* A()

   {

      scalarField * a = new scalarField(1e5,0);

      return a; //返回局部变量a

   }

   scalarField* aa=A(); 这时候aa指向函数内局部变量申请的空间;

如果用tmp来实现

tmp<scalarField> A()

{

    tmp<scalarField> a (new scalarField(1e5,0));

    return a;

}

tmp<scalarField> a = A();

上述两种方法都可以正确执行,但是第一种方法极易出现内存漏洞和其他程序问题 比如下面程序;

在上面第一段程序后加上下面一段;

aa = new scalarField (10,0);

上面的意思是aa不再指向堆中的内存,而是指向重新申请的堆空间,以前申请的空间就不会被释放出现内存漏洞。当然你可以在aa指向新空间时候,将aa释放掉,比如

delete aa;

aa = new scalarField (10,0);

这样执行没有问题了就;

但是如果还有可能出现这种情形;

scalarField *bb =aa;

delete aa;

aa = new scalarField(10,0);

这时候就有问题了,因为bb指向aa的空间,但是aa被释放掉了,bb就是一个指向释放掉的指针。 等等。。。此类问题会很多。

tmp通过refCount来记录当前有多少个指针指向该空间,来决定是否释放,如果该指针被其他指针赋值,只需要将refcount减少1即可,如果refercount为0了,自动释放即可。避免了上述的所有问题。所以,合理使用tmp不仅可以提高效率,而且可以避免内存泄露等问题。当然tmp对象可以直接手动释放内存,通过clear函数来实现;

3)tmp怎么用



这点不用说了,在前面的这段程序已经说明白了

tmp<scalarField> A()

{

//new 一下,必须new才能返回,也就是堆中数据才能返回否则的话,编译器会给你释放掉;

    tmp<scalarField> a (new scalarField(1e5,0));   

    return a;

}

tmp<scalarField> a = A();



由于该类使用的refCount来记录被类对象被引用的次数,因此只有refCount的子类才可以作为tmp的参数来使用。 OpenFOAM中的Field及其子类都是refCount的子类。使用它可以提高效率;



不妨试一试。 祝好

转自OpenFOAM研究: http://blog.sina.com.cn/openfoamresearch
页: [1]
查看完整版本: OpenFOAM瞬态对象模板类tmp的分析及其使用