Symbian OS 精要 |
| 作者:未知 来源:转载 发布时间:2006-11-30 22:16:59 |
|
• 用可能不存在于您的析构函数中的变量调用函数。 例如,以下代码可能导致异常,因为有可能您在分配 内存之前您的对象已经被销毁,或者在应用程序的另 一处已经删除了该内存,这样iSomeServer 就会处 于NULL: CMyClass::~CMyClass() { iSomeServer->Close(); delete iSomeServer; } 应该如下编写代码: CMyClass::~CMyClass() { if (iSomeServer) { iSomeServer->Close(); delete iSomeServer; } } • 在NULL 指针上调用函数。 • 函数调用另一个函数,而其使用的变量已经超出范畴, 例如:把一个栈变量传送到一个异步函数的回调 (callback) 里。 6. 在系统资源不够的情况下,得体的处理失效情况是非 常重要的。最受限制的资源通常是系统RAM,因此 您需要注意正确的处理内存不足的情况。采用‘两段 构造方法’和如下所述的CleanupStack 机制,对这 种防御性编程来说是必不可少和极其重要的。 7. 对带“R”字头、具备Close()方法的类,总是使用 CleanupClosePushL()。这将确保当Leave 事件 发生时,它们会被恰当的清除。例如: RFile file; User::LeaveIfError(file.Open(…)); CleanupClosePushL(file); … CleanupStack::PopAndDestroy(&file); 对用Release()或Destroy()的‘R’ 类,亦可使用 CleanupDeletePushL()及 CleanupReleasePushL()来取代Close()。 8. 另外,请记住CleanupStack 机制是可扩展的,面 对所有Leave 事件,都可以用它来有效的清除任 何对象。即使您需要处理的是较复杂的情况,也 不应该忽略采用正规的清理机制。欲进一步了解 TCleanupItem,请参阅Symbian OS Library 文档。 9. 倘若您意图对HBufC 变量重新分配资源,在清除它 们之后,总是将其设为NULL。由于HBufC 的资源 分配或其再分配可能会导致Leave 事件的发生,从而 可能会出现析构函数试图删除已经不存在的HBufC 变量的情况。当然,对于任何由堆分配资源的变量而 言都应如此,对HBufC 变量采取此做法更是已经成 为普遍的使用模式。 10. 当必须采用自己的TRAP 时,请勿忽略所有的报错。 常见的编码错误是: TRAPD(err, DoSomethingL()); if (err == KErrNone || err == KErrNotFound) { // Do something else } 这意味着其他错误码都被忽略。然而,倘若您非用上 述模式不可,应采用Leave 机制来处理其他错误: TRAPD(err, DoSomethingL()); if (err == KErrNone || err == KErrNotFound) { // Do something else } else User::Leave(err); 11. 不要延误将对象PushL()到CleanupStack 上。所 有新创建的对象(成员变量除外)应被立即压入该堆 栈。例如,下面的作法是错的: void doExampleL() { CSomeObject* myObject1=new (ELeave) CSomeObject; CSomeObject* myObject2=new (ELeave) CSomeObject; … // Do something here with thevariables CleanupStack::PushL(myObject1); CleanupStack::PushL(myObject2); // Do something more with the variables … CleanupStack::PopAndDestroy(2); // myObject2, myObject1 } 因为myObject2 的创建可能失败,造成myObject1 “悬”在那里不能被清理。应该这样来实现: void doExampleL() { CSomeObject* myObject1=new (ELeave) CSomeObject; CleanupStack::PushL(myObject1); CSomeObject* myObject2=new (ELeave) CSomeObject; CleanupStack::PushL(myObject2); … // Do something here with the variables … CleanupStack::PopAndDestroy(2); // myObject2, myObject1 } 12. 注意,那些名称有大写字母C 结尾的函数(例如 NewLC())会自动把其对象置于CleanupStack。 您不应该自己来将这些对象压入CleanupStack, 否则该对象会入栈两次。当您创建非成员变量并为其 分配内存时,这些由C 结尾的函数很有用。 13.“两段构造方法”是Symbian OS 内存管理的关键 部分。基本原则是Symbian OS 中的构造函数或析 构函数永远不应该发生Leave。倘若一个C++ 构造 函数Leave,构造过程未完成的对象得不到清理, 因为还没有生成指针指向该对象。为此,Symbian OS 中的构造函数仅将该对象实例化,而后调用该 对象的ConstructL()函数,在其中将成员数据 实例化。一旦ConstructL()发生Leave,标准 的析构函数将被调用来清除所有至此已被成功分 配的成员变量。在您的编码中照用这一设计模式 来防止内存泄漏,至为关键。当您写每一行代码 时, 都应该问自己:“ 这一行代码能否发生 Leave ?”假如回答为“是”,则应考虑“是否所 有资源都将被释放?”。 14. 编码中请勿使用_L()宏——而应使用_LIT()。_L() 自Symbian OS v5 起已是‘不推荐使用’(deprecated), 它的问题在于它将调用TPtrC(const TText*)构造 函数,该构造函数会调用strlen()函数来计算该字串的长度。虽然这不会带来额外的RAM 开销,却会 在运行时占用更多CPU 周期。相反,宏_LIT()直接 创建了一个在编译时就全部实例化的对象,节省了构 造TPtrC 的CPU 开销。当然,您首先应该考虑的是 否应该使用硬编码的字符串常量,因为当您将来地方 化(localize)您的程序时,这种常量类型的描述符 (descriptor) 可能需要重新编码。 15. 当在函数参数中使用描述符(descriptor) 时,应缺省 使用基类。在大多数情况下,以const TDesC& 形 式来传递描述符。对可修改的描述符,则应使用 TDes&。 16. 当在函数中传递或返回对象时,应确保如果您拥有该 对象的所有权,您应负责将其清除! Symbian 采取 的约定是:函数中的指针表示所有权转移到调用者, 而使用引用则表示被传递对象的所有权仍属于原所 有者。 17. Active Objects 是Symbian OS 的重要特性之一。请仔细 研究SDK 文档、Symbian Developer Network 白皮书, 以充分理解其工作原理。下面是一些有用的窍门: • 在RunL()内无需使用TRAP()。Active Scheduler 本身会TRAP 函数RunL()并在其发生Leave 时 调用CActive::RunError()。 • 为此,您应实现自己的RunError()函数来处 理从RunL()的Leave 事件。 • 保证RunL()操作尽可能简短。长时间运行的 RunL()将阻塞其他Active Objects。 • 总是实现DoCancel()函数,总是在AO 析构 函数中调用Cancel()。 18. 您应尽可能利用Active Object 框架机制。对于使用电 池供电的设备,在一个循环中紧密不断地进行轮流 检测(polling) 是极其不适当的,将带来 |
| [] [返回上一页] [打 印] |
|
文章评论 |
