如何避免常见错误并建立更有效的编程
文章信息
参照下列提示以便避免不需要的和常规的错误,并建立更有效的编程
Contents |
KERN-EXEC 3
当栈损坏或栈溢出时经常会发生Kern-Exec 3错误,建议多用heap代替stack。注意像递推函数可能会在运行时吞噬栈空间,这将导致Kern-Exec 3异常发生。
一些程序异常的常见错误
- 增加非成员,堆栈分配的变量到清除栈所引发的错误
- 双重删除错误,如Pop()一个从清除栈已经删除的项目,将会引发stack重复删除行为
- 在析构函数中访问可能已经不存在的函数。
如
CSomeClass::~CSomeClass()
{
iServer->Close();
delete iServer;
}
上述代码应该修改为:
CSomeClass::~CSomeClass ()
{
if (iServer)
{
iServer ->Close();
delete iServer;
}
}
- 将成员变量放入清除栈——不要这样做,只需在析构函数中删除即可。
使用CleanupClosePushL()
对有Close()方法的R类使用CleanupClosePushL()方法,这样可以保证他们能够在异常发生时正确被清除。
例如:
RFile file;
User::LeaveIfError(file.Open(.....));
CleanupClosePushL(file);
// some code
CleanupStack::PopAndDestroy();
HBufC
删除之后要设置为NULL,因为HBufC的分配(或重新分配)可能会发生异常
你不需要使用HBufC::Des()来获取HBufC,你只需要通过HBufC*来引用,这是相关联的,当要传递HBufC总是使用TDesC&做参数
_L()宏
不要使用_L()宏在你的代码中,你应该使用_LIT()取代。使用_L()的问题是它调用了TPtrC(const TText)构造函数,它需要调用strlen()函数以便计算出字符串长度。尽管它不会消耗多余的ram,但它在运行时消耗了CPU,而_LIT()宏则直接构造了一个结构,它在编译时全部初始化了,因此它节省了CPU在构造TPtrC时的消耗了。
另外,你可以使用下列宏来取代_L()
#define __L(a) (TPtrC((const TText *)L ## a,sizeof(L##a)/2-1))
#define __L8(a) (TPtrC8((const TText8 *)(a),sizeof(a)-1))
#define __L16(a) (TPtrC16((const TText16 *)L ## a,sizeof(L##a)/2-1))
它跳过了strlen,但TPtrC构造不是inline函数
TRAP
如果你要使用TRAP,不要忽略所有的错误。常用编码如下:
TPAPD(err, SomeFunctionL());
if (err == KErrNone || err == KErrNotFound)
{
// Do something else
}
这个意味着所有其他的错误代码都可以忽略,如果你照上面的操作,请加上其他错误的leave部分
TPAPD(err, SomeFunctionL());
if (err == KErrNone || err == KErrNotFound)
{
// Do something else
}
else
User::Leave(err);
清除栈
不要等待PushL()在清除栈上,任何新分配的对象(除了成员变量)都需要立刻增加到stack,如下是错误的编码
void doExampleL()
{
CSomeObject* Object1=new (ELeave) CSomeObject;
CSomeObject* Object2=new (ELeave) CSomeObject;
}
因为Object2的分配可能会失败,那么就导致Object1没有办法清除干净,下面是正确做法:
void doExampleL()
{
CSomeObject* Object1=new (ELeave) CSomeObject;
CleanupStack::PushL(Object1);
SomeObject* Object2=new (ELeave) CSomeObject;
CleanupStack::PushL(Object2);
}
不要将对象推入清除栈2次
记住函数名后面有C后缀的会自动将对象纳入清除栈,你不需要再将这些对象推送到栈内。当你分配非常成员变量时这个带C后缀的函数是很有用的。
两段式构造
两段式构造是为内存泄漏特别制造的,可以用来防止程序的内存泄漏。没写一行代码你都要问自己是否会引发异常?如果回答是,那就要考虑这些资源如何被释放?
作为函数参数的描述符
当使用描述符来做函数参数时,一般传递const TDesC&为参数格式,如果是可变描述符则为TDes&
当使用Active Object时注意下列事项
- 不需要在RunL()中调用TRAP()。Active Scheduler自己已经TRAP了RunL(),并在发生异常时调用CActive::RunError()
- 你需要完成自己的RunError()函数来处理RunL()的异常
- 要保证RunL()尽可能短和快,较长的执行操作会阻塞AO的操作
- 一定要完成DoCancel(),并在AO析构时调用Cancel()方法
确保你的程序能相应系统关闭事件
注意在AppUi::HandleCommandL()方法里响应EEikCmdExit(或任何平台相关的事件,如S60中的EAknSoftkeyBack和EAknCmdExit
事件。
尽可能使用Active Object框架
Tight polling in a loop is highly inappropriate on a battery powered device and can lead to significant power drain.
WINS编译通过但ARMI平台失败
你的程序在模拟器上可能编译通过,但在ARMI编译时却会报错。可能是因为你在头文件名中留了一个空格,如#include "headerfile.h "应该替换为#include "headerfile.h",然后再重新编译试试。
HTTP Post请求
注意HTTP Post请求时总要记得删除CHTTPFormEncoder实例,如果你服务器是php那么表格元素就会从底到顶依次读取,如果是python脚本就会从头至尾读。所看起来能在php工作的代码不一定能在python工作,所以需要执行如下:
delete iFormEncoder;
iFormEncoder = NULL;
iFormEncoder = CHTTPFormEncoder::NewL();


(no comments yet)