博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Symbian 智能指针(转)
阅读量:2496 次
发布时间:2019-05-11

本文共 5772 字,大约阅读时间需要 19 分钟。

在Symbian开发过程中, 由于没有确定性析构, 最让人烦躁的就是Cleanup Stack的操作, 当在一个函数中使用局部变量时,
要记得PushL, 然后在函数末尾, 还要PopAndDestroy, 变量一多, 头昏脑胀,都找不到北了, 经常被Panic, 而且在VC6窗口
中还不知道到底是哪行的问题, 只能单步调试, 一直到程序crash. 然后知道上一行就是问题所在.
下面是我写的一个智能指针类( 实际上是两个, 一个CPtr用于C class, 一个RPtr 用于R class), 我自己的使用经验表明可以免除90%的对Cleanup Stack的操作. (实际上我在新代码中从来不再手动使用CleanupStack了)
例如一个简单的代码:
void FunL()
{
HBufC * wbuf = HBufC::NewL(10);
CleanupStack::PushL(wbuf); //有点造作, 应该直接的用HBufC::NewLC, 仅仅是举个例子, 因为很多类只提供了NewL
HBufC * wbuf2 = HBufC::NewL(20);
CleanupStack::PushL(wbuf2);
RFs fs;
User::LeaveIfEror( fs.Connect());
CleanupClosePushL(fs);
do_sth_maybe_leaveLLL();
CleanupStack::PopAndDestroy(3); //关文件fs, 删除wbuf, wbuf2
}
如果函数中又增加一个C对象的使用, 那么要手动PushL一次, 然后在结尾还要记得将PopAndDestroy(3) 改为 4.
如果利用智能指针, 上面的代码可以简化为:
void FunL()
{
using namespace sbl; //封装在sbl中
CPtr wbuf(HBufC::NewL(10)); //永远不要调用NewLC, CPtr内部会PushL的
CPtr wbuf2(HBufC::NewL(20)); //同上
RPtr fs;
User::LeaveIfEror( fs->Connect()); //fs.Connect() 改为 fs->Connect()
do_sth_maybe_leaveLLL();
}
以后就什么都不用管了, Leave也好, 不Leave也好, wbuf, wbuf2最终都会被delete, fs都会被关闭.
记住的是:
1. 不要对成员变量使用CPtr, RPtr (你应该知道, 成员变量本身就不应该PushL)
2. 在一个函数中不要混合使用CleanupStack 和 智能指针类. 要不你就手动的PushL, 要不就全部交给智能指针.
3. 在给CPtr智能指针初始化/赋值的时候, 永远不要调用Cxxx::NewLC, (因为NewLC自己PushL一次了), 而总是调用NewL.
另外, 有了智能指针, 基本上你无需再给你的class提供NewLC了, 而且NewL中的实现可以如下:
/* static */
CFoo * CFoo::NewL()
{
CPtr self( new (ELeave)CFoo); //放心, CPtr内部已经PushL了, 保护了这个self
self->ConstructL(); //Leave也无问题, 会调用delete self的.
return self.release(); //release 释放所有权, 这样CPtr析构的时候不会再去delete self.
}
基本上, 你了解STL中的auto_ptr, 也就了解了CPtr. RPtr有点不同, 主要用于使用R class, 它内部放的不是T*,而是直接T本身.
再举个CPtr的例子:
void foo()
{
CPtr wbuf(HBufC::NewL(20)); //分配内存
*wbuf = _L("Hello,world"); //给 HBufC 赋值
wbuf = 0; //释放, 注意HBufC已经释放了, 或者 reset(0)也可以
wbuf = HBufC::NewL(20); //又分配内存
wbuf = HBufC::NewL(40); //哎呀, 不够, 释放刚刚分配的, 分配一块大的内存
*wbuf = _L("long long long hello, world ");
}
基本上和stl中的auto_ptr使用没有什么分别. 不过由于symbian的cleanup机制, 不能将CPtr/RPtr作为成员变量.
下面是源代码: (使用的时候别忘了CPtr, RPtr都是在sbl namespace中, 另外, debug版本中用到了c library的assert)
#include
#include
#include
namespace sbl //sbl stands for SymBian Library
{
// a auto_ptr for any object can be free by "delete" operator
// if you know std::auto_ptr then no much thing you need to study
template
class CPtr
{
public:
//take a raw pointer, this pointer must not been pushed into cleanup stack
explicit CPtr(T* ptr = 0) : ptr_(ptr)
{
//no matter how we need a slot in cleanup stack
CleanupPushL();
}
//copy ctor, take ownership, just like std::auto_ptr
CPtr(CPtr& other)
{
ptr_ = other.release();
CleanupPushL();
}
//assignment, take ownership, just like std::auto_ptr
CPtr& operator=(CPtr& other)
{
if(this != &other) {
assert( ptr_ != other.ptr_);
reset(other.release());
}
return *this;
}
CPtr& operator=(T* ptr)
{
reset(ptr);
return *this;
}
/* sorry, due to buggy vc6
template
CPtr(CPtr& other)
{
CleanupPushL();
ptr_ = other.release();
}
template
CPtr& operator=(CPtr& other)
{
reset(other.release());
reutrn *this;
}
*/
T& operator*() const
{
assert(ptr_ != 0);
return *ptr_;
}
T* operator->() const
{
assert(ptr_ != 0);
return ptr_;
}
// get the raw pointer explicitly
T* get() const
{
return ptr_;
}
void reset(T* ptr = 0)
{
if(ptr != ptr_)
{
delete ptr_; // here we use "delete" to free resource
ptr_ = ptr;
}
}
// release ownership
T* release()
{
T* tmp = ptr_;
ptr_ = 0;
return tmp;
}
//normally exit, dispose
~CPtr()
{
CleanupStack::PopAndDestroy(1, this); // remove from cleanup stack
}
typedef void (*safe_bool)(void *p);
// used by if (c)
operator safe_bool() const
{
return ptr_ ? &Dispose : 0;
}
//used by if(!c)
bool operator!() const
{
return safe_bool(*this) == 0;
}
private:
T* ptr_;
void CleanupPushL()
{
CleanupStack::PushL(TCleanupItem(OnLeave, this));
}
static void OnLeave(void * p);
};
//this function isn't inline since cleanup stack want our function pointer
template
void CPtr::OnLeave(void * p)
{
CPtr * cptr = static_cast(p);
cptr->reset(0);
}
//default R class uses Close() to release resource
template
class RTrait
{
public:
static void Dispose(R& r)
{
r.Close();
}
static bool Connected(const R& r);
};
// default R class check binary bits to determine if connected
template
bool RTrait::Connected(const R& r)
{
const char * start = (const char *)&r;
const char * end = start + sizeof(R);
for(; start != end; start++)
{
if ( *start != 0)
return true;
}
return false;
}
template >
class RPtr
{
public:
RPtr()
{
assert(!Trait::Connected(res_));
CleanupStack::PushL(TCleanupItem( OnLeave, this));
}
template
RPtr(const A1& a) : res_(a)
{
CleanupStack::PushL(TCleanupItem( OnLeave, this));
}
/*
template
RPtr(const A1& a1, const A2& a2) : res_(a1, a2)
{
CleanupStack::PushL(TCleanupItem( DisposeInvoker, this));
}
template
RPtr(const A1& a1, const A2& a2, const A3& a3) : res_(a1, a2, a3)
{
CleanupStack::PushL(TCleanupItem( DisposeInvoker, this));
}
*/
~RPtr()
{
CleanupStack::PopAndDestroy(1, this); // remove from cleanup stack and delete
}
R* operator->()
{
return &res_;
}
R& operator*()
{
return res_;
}
R& get()
{
return res_;
}
operator R& ()
{
assert( safe_bool(*this));
return res_;
}
typedef void (*safe_bool)(void*);
// used by if(r)
operator safe_bool() const
{
return Trait::Connected(res_) ? &OnLeave : 0;
}
//used by if(!r)
bool operator!() const
{
return safe_bool(*this) == 0;
}
private:
R res_;
static void OnLeave(void * p);
//noncopyable and assignable
RPtr& operator=(const RPtr&);
RPtr(const RPtr&);
};
template
void RPtr::OnLeave(void * p)
{
RPtr* self = static_cast< RPtr*>(p);
// if(*self) to check if the R class is connected
if(*self) {
Trait::Dispose(self->res_);
assert(!Trait::Connected(self->res_));
}
}
} //end of namespace
#endif

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10294527/viewspace-126429/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10294527/viewspace-126429/

你可能感兴趣的文章
hdu 1069 Monkey and Banana
查看>>
C语言----结构体---结构体与函数
查看>>
JavaScript DOM知识 (一)
查看>>
B-树和B+树的应用:数据搜索和数据库索引
查看>>
Chrome DevTools 的 Sources 调试
查看>>
关于web前端中文站(www.lisa33xiaoq.net)侵权业余草(www.xttblog.com)相关文章的公告...
查看>>
执行umount 的时候却提示:device is busy 的处理方法
查看>>
nginx 服务器重启命令,关闭
查看>>
linux命令sed学习笔记
查看>>
2016年的不正式总结
查看>>
图文介绍openLDAP在windows上的安装配置
查看>>
优化UITableViewCell高度计算的那些事(RunLoop)
查看>>
Source Insight上手教程
查看>>
Xamarin.forms--------------Picker
查看>>
C++ 并发编程实战
查看>>
Asp调用MVC后部署服务器
查看>>
C# XML操作类
查看>>
bzoj1998: [Hnoi2010]Fsk物品调度
查看>>
选择监听事件ItemListener(是否被选择)
查看>>
java web开发(一) 环境搭建
查看>>