Symbian 智能指针

Symbian 智能指针
在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
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值