|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
今天讨论一下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 |
|