Symbian 智能指针

原创 2007年09月21日 14:51:00

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
 

c++11智能指针解析——揭开底层面纱,完整理解智能指针

昨天跟同事小小的研究了下关于不同平台下,起因是遇到了一个坑,vs上没有问题,在安卓上却崩溃了。找了半天后发现是c++字节补齐问题,期间包括使用#pragma pack(1)来限定字节对齐方式等各种条件...
  • zy19940906
  • zy19940906
  • 2016年01月07日 17:00
  • 9259

C++四种智能指针小结

C++四种智能指针auto_ptr、scope_ptr、shared_ptr和weak_ptr. 其中auto_ptr是C++98标准化引入的;scope_ptr、shared_ptr和weak_p...
  • e5Max
  • e5Max
  • 2016年01月23日 12:33
  • 2790

Android系统篇之----Android中的智能指针

一、前言今天我们开启Android系统篇的文章了,其实一直想弄,只是之前一直没有太多深入的了解,最近又把这块拿出来好好看了一下,所以想从新梳理一下,来看看Android中的这块知识,首先我们今天来看一...
  • jiangwei0910410003
  • jiangwei0910410003
  • 2016年05月03日 17:27
  • 9640

C++11新特性之智能指针

这一节将从用法上、内存存储上以及生存周期上,对unique_ptr, shared_ptr和weak_ptr做一个深入剖析。unique_ptr   不共享它的指针。它无法复制到其他 unique...
  • u013184159
  • u013184159
  • 2016年04月18日 10:57
  • 6389

C++为什么要用智能指针

首先要理解什么是智能指针。  先来看普通指针,int *p = new int; 这个p 是一个普通指针,指向一个内存块,内存块中存放一个整形数值。 而智能指针是在普通指针的基础上,加上一个引用计...
  • snail_hunan
  • snail_hunan
  • 2015年01月24日 16:22
  • 827

c++11智能指针解析——揭开底层面纱,完整理解智能指针

http://blog.csdn.net/zy19940906/article/details/50470087  本次讨论:c++11之前的auto_ptr; c++11新加的unique_p...
  • gettogetto
  • gettogetto
  • 2017年03月27日 09:52
  • 344

c++ 复制控制和智能指针实现

总结了c++中三种复制控制的场合和具体实现方法,在此基础上设计自己的智能指针类。...
  • wenzhou1219
  • wenzhou1219
  • 2016年06月04日 21:02
  • 1352

四种智能指针的用法和原理

智能指针共分为4种,即boost库中的auto_ptr、scoped_ptr、shared_ptr、weak_ptr。   智能指针的作用是管理一个指针,因为存在以下这种情况:申请的空间在函数结束时...
  • sinat_36118270
  • sinat_36118270
  • 2017年04月04日 13:06
  • 860

C++面试题(四)——智能指针的原理和实现

普通C++面试时候的一般都是这个套路:      1,C++和C相比最大的特点——面向对象:封装,继承,多态。      2,你知道虚函数吗?——实现多态所必须,父类类型的指针指向子类的实例,执行的时...
  • worldwindjp
  • worldwindjp
  • 2014年01月28日 17:00
  • 11626

stl智能指针和boost智能指针对比

先说说stl中的智能指针auto_ptr,先说说auto_ptr的特点。std::auto_ptr用来管理单个堆内存对象,但是独享所有权,且不允许赋值和拷贝(没有重载operator=),所以如果在函...
  • zhangqi_gsts
  • zhangqi_gsts
  • 2015年12月14日 20:15
  • 1199
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Symbian 智能指针
举报原因:
原因补充:

(最多只允许输入30个字)