Symbian 智能指针(转)

此内容为来自ITPUB博客的转载声明,给出了博客链接,强调转载需注明出处,否则将追究法律责任。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值