一,Symbian程序编程规范
1, 类名、函数名、常量的第一个字母大写
2, 类成员变量、函数形参第一个字母小写
3, 函数名以大写L结尾表示函数在执行时可能会产生异常
4, 宏命名必须以下划线开头,并且名字中各个单词用下划线隔开
5, 枚举名称以T开头
6, 类名通常以C、T、M、R开头
C开头的类,都从CBase继承而来,C类的所有对象只能放在堆上。
T开头的类,是普通类,如Tint、TUInt等,该类的所有对象既可以在栈上也可以在堆上
M开头的类,只表示一个接口,只包含纯虚函数
R开头的类,是资源类
二,Symbian OS 的内存处理机制
1, TRAP和TRAPD
2, 清理栈
3, 两阶段构造函数
自己对三者的理解:
1, TRAP和TRAPD同C++中的catch{}try差不多,TRAP和TRAPD有一个out参数err,
举个例子 : Tint err ; TRAP( err , B())
如果函数B()没发生异常,err就会被赋值0 ,否则返回非0
我们就可以根据err值进行异常处理。TRAP和TRAPD并不能对函数B中的内存泄漏
进行处理。但是清理栈可以解决这个问题。
2, 以B函数为例,清理栈主要是解决在B函数中申请的内存但在B函数后面(还是在 B函数中)的代码出现异常,显然如果我们没有Push,之前申请的内存就会泄漏,如果用push 就会解决这个问题。
3, 两阶段构造函数,是为了解决在构造函数中为成员变量赋值失败而产生内存泄漏(此时类对象已经在堆上申请了内存空间。
我试想用TRAP和清理栈来代替两阶段构造函数。
两阶段构造函数:
A*A::CreateL()
{
A* m = new ((ELeave)A ; (1) 第一层构造函数
Cleanupstack::PushL(m) ;
m->CreL() ; (2)第二层构造函数
Pop(m)
}
A::CreL()
{
n = new (Eleave)B ;
Cleanupstack::PushL(n) ;
MMML()
Pop(n) ;
}
如果用TRAP代替:
A::A()
{
PushL(this) ;
n = new (Eleave)B ;
} ;
Void MMM()
{
Tint err ;
A *a = 0 ;
Trap( err , a = new A ) ;
If( !err)
{
Pop(a) ;
}
}
问题:
MMML()
{
}
class Test1:public CBase
{
} ;
class CTest:public CBase
{
public:
Tint m ;
Test1 * n ;
CTest() ;
static CTest * MCreateL() ;
Test1 * ML() ;
} ;
CTest * CTest::MCreateL()
{
CTest *q = new (ELeave)CTest ;(1)
Cleanupstack::PushL(q) ; (2)
q->ML() ;
Cleanupstack::Pop() ;
return q ;
}
Test1 * CTest:ML()
{
n = new (ELeave)Test1 ;
Cleanupstack::PushL(n) ;
MMML() ;
Cleanupstack::Pop() ;
}
CTest::CTest()
{
m = 0 ;
}
void Cmen()
{
CTest *q = CTest::MCreateL();
CleanupStackStack::PopAndDestroy() ;
}
问题1:在(1)中不会产生异常,所以认为(2)行可以去掉
解决:这种想法是错误的,之所以用PushL(),是为了防止其后面的代码会发生异常而产生内存泄漏
跟前面行是否发生异常没有关系。
另外最美好的设计模式是PushL()和Pop()在同一个函数中,这样可以避免自己(或他人)在别的
地方调用Pop()或是PopAndDestroy()时产生错误(因为别人并不知道在其他函数中已经Push过,
而没有Pop。
问题2:CleanupStackStack::PopAndDestroy() 是不是在任何一个程序中都必须有?
解决:不是,当发生了异常,那么只是执行了Push,而没有Pop ,最后程序会自动将栈中对象删除。