×
Namespaces

Variants
Actions

如何避免常见错误并建立更有效的编程

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

文章
翻译:
hoolee
最后由 hamishwillee 在 22 Dec 2011 编辑

参照下列提示以便避免不需要的和常规的错误,并建立更有效的编程

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();
This page was last modified on 22 December 2011, at 07:46.
55 page views in the last 30 days.