Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

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

From 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 04:46.
88 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×