分享
 
 
 

Symbian 智能指针

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

在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<HBufC> wbuf(HBufC::NewL(10)); //永远不要调用NewLC, CPtr内部会PushL的

CPtr<HBufC> wbuf2(HBufC::NewL(20)); //同上

RPtr<RFs> 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<CFoo> 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<HBufC> 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 <e32base.h>

#include <libc/assert.h>

#include <libc\string.h>

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 T>

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<T>& other)

{

ptr_ = other.release();

CleanupPushL();

}

//assignment, take ownership, just like std::auto_ptr

CPtr<T>& operator=(CPtr<T>& other)

{

if(this != &other) {

assert( ptr_ != other.ptr_);

reset(other.release());

}

return *this;

}

CPtr<T>& operator=(T* ptr)

{

reset(ptr);

return *this;

}

/* sorry, due to buggy vc6

template<class U>

CPtr(CPtr<U>& other)

{

CleanupPushL();

ptr_ = other.release();

}

template<class U>

CPtr<T>& operator=(CPtr<U>& 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<class T>

void CPtr<T>::OnLeave(void * p)

{

CPtr * cptr = static_cast<CPtr*>(p);

cptr->reset(0);

}

//default R class uses Close() to release resource

template<class R>

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<class R>

bool RTrait<R>::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 R, class Trait = RTrait<R> >

class RPtr

{

public:

RPtr()

{

assert(!Trait::Connected(res_));

CleanupStack::PushL(TCleanupItem( OnLeave, this));

}

template<class A1>

RPtr(const A1& a) : res_(a)

{

CleanupStack::PushL(TCleanupItem( OnLeave, this));

}

/*

template<class A1, class A2>

RPtr(const A1& a1, const A2& a2) : res_(a1, a2)

{

CleanupStack::PushL(TCleanupItem( DisposeInvoker, this));

}

template<class A1, class A2, class A3>

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<class R, class Trait>

void RPtr<R, Trait>::OnLeave(void * p)

{

RPtr<R, Trait>* self = static_cast< RPtr<R, Trait>*>(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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有