Symbian C++ 引发的问题

一、       引言:

最近因为要在symbian系统上移植STL库,因为symbian编译器与windows的编译器的不同,因此产生了诸多代码代码在windows平台下可以编译并运行正常,而在symbian系统上却编译不通过,或产生一定的运行错误,下面根据自己在研发过程中遇到的实际问题进行论述;

 

二、       问题的阐述

1、           编写C++标准库的auto_ptr产生的问题:

   auto_ptr是当前C++标准库中提供的一种智能指针,主要是让资源在局部对象构造时分配,在局部对象析构时释放;

与引用计数型智能指针不同的,auto_ptr要求其对指针的完全占有性。也就是说一个指针不能同时被两个以上的auto_ptr所拥有。那么,在拷贝构造或赋值操作时,我们必须作特殊的处理来保证这个特性。auto_ptr的做法是所有权转移,即拷贝或赋值的源对象将失去对指针的所有权,所以,与一般拷贝构造函数,赋值函数不同, auto_ptr的拷贝构造函数,赋值函数的参数为引用而不是常引用(const reference).当然,一个auto_ptr也不能同时拥有两个以上的指针,所以,拷贝或赋值的目标对象将先释放其原来所拥有的对象。

   正是由于拷贝构造函数和赋值函数的上述设计,导致了下面的代码的设计(除了蓝色部分的代码)的auto_ptr()不能构造右值(标准C++规定,如果一个右值作为函数的参数,这个参数的定义必须是const的,因为右值为常量或临时变量——如函数的返回值);

 

通过特殊转换auto_ptr_ref

 

这里提供一个辅助类auto_ptr_ref来做特殊的转换(蓝色部分),

我们本来就可以拷贝和赋值non-constauto_ptr和禁止拷贝和赋值constauto_ptr的功能, 只是无法拷贝和赋值临时的auto_ptr(右值), 而这些辅助代码提供某些转换,使我们可以拷贝和赋值临时的auto_ptr,但并没有使constauto_ptr也能被拷贝和赋值。如下:

auto_ptr<int> ap1 = auto_ptr<int>(new int(0));

auto_ptr<int>(new int(0))是一个临时对象,一个右值,一般的拷贝构造函数当然能拷贝右值,因为其参数类别必须为一个const reference, 但是我们知道,auto_ptr的拷贝函数其参数类型为reference,所以,为了使这行代码能通过,我们引入auto_ptr_ref来实现从右值向左值的转换。其过程为:

1) ap1要通过拷贝 auto_ptr<int>(new int(0))来构造自己

2) auto_ptr<int>(new int(0))作为右值与现有的两个拷贝构造函数参数类型都无法匹配,也无法转换成该种参数类型

3) 发现辅助的拷贝构造函数auto_ptr(auto_ptr_ref<T> rhs) throw()

4) 试图将auto_ptr<int>(new int(0))转换成auto_ptr_ref<T>

5) 发现类型转换函数operator auto_ptr_ref<Y>() throw(), 转换成功,从而拷贝成功。

 

而通过一个间接类成功的实现了拷贝构造右值(临时对象)

同时,这个辅助方法不会使const auto_ptr被拷贝, 原因是在第5步, 此类型转换函数为non-const的,我们知道,const对象是无法调用non-const成员的, 所以转换失败。当然, 这里有一个问题要注意, 假设你把这些辅助转换的代码注释掉,在vs2008环境下进行编译,该行代码还是可能成功编译,这是为什么呢?debug一下, 我们可以发现只调用了一次构造函数,而拷贝构造函数并没有被调用,原因在于编译器将代码优化掉了。这种类型优化叫做returned value optimization,它可以有效防止一些无意义的临时对象的构造。当然,前提是你的编译器要支持returned value optimizationvs的编译器就支持。

 

template<class Type>

struct auto_ptr_ref

{

    Type* _ref;

    explicit auto_ptr_ref(Type* right)

       :_ref(right)

    {

    }

};

 

template <typename T>

class auto_ptr {

public:

    typedef T      value_type;

    typedef T*     pointer;

    typedef T&     reference;

public:

    inline explicit   auto_ptr (pointer p = NULL) : m_p (p) {}

 

    inline     auto_ptr (auto_ptr<T>& p)   : m_p (p.release()) {}

 

    inline auto_ptr (auto_ptr_ref<T> right )

    {

       pointer _Ptr = right._ref;

       right._ref = 0;   // release old

       m_p = _Ptr;   // reset this

    }

 

    template<class _Other>

    operator auto_ptr_ref<_Other>()

    {  

       _Other *_Cvtptr = m_p;  

       auto_ptr_ref<_Other> _Ans(_Cvtptr);

       m_p = 0;  

       return (_Ans);

    }

 

    inline         ~auto_ptr (void)          { delete m_p; }

 

    inline pointer get (void) const     { return (m_p); }

 

inline pointer    release (void)           { pointer rv (m_p); m_p = NULL; return (rv); }

 

inline void       reset (pointer p = NULL)    { if (p != m_p) { delete m_p; m_p = p; } }

 

inline auto_ptr<T>&  operator= (pointer p)       { reset (p); return (*this); }

 

inline auto_ptr<T>&  operator= (auto_ptr<T>& p)  { reset (p.release()); return (*this); }

 

    inline auto_ptr<T>& operator=(auto_ptr_ref<T> right)

    {  

       pointer Ptr = right._ref;

       right._ref = 0;   // release old

       reset(Ptr);   // set new

       return (*this);

    }

 

 

    inline reference  operator* (void) const      { return (*m_p); }

    inline pointer operator-> (void) const     { return (m_p); }

    inline bool       operator== (const pointer p) const { return (m_p == p); }

    inline bool       operator== (const auto_ptr<T>& p) const   { return (m_p == p.m_p); }

inline bool       operator< (const auto_ptr<T>& p) const { return (p.m_p < m_p); }

private:

    pointer    m_p;

};

 

 

2、             Symbian对模版的嵌套的支持性:

如下代码

 

template <typename ConstPointer, typename Compare>

int qsort_adapter (const void* p1, const void* p2)

{

    ConstPointer i1 = reinterpret_cast<ConstPointer>(p1);

    ConstPointer i2 = reinterpret_cast<ConstPointer>(p2);

    Compare* comp = (Compare*)g_sort;

    return ((*comp) (*i1, *i2) ? -1 : ((*comp) (*i2, *i1) ? 1 : 0));

}

 

template <typename RandomAccessIterator, typename Compare>

void sort (RandomAccessIterator first, RandomAccessIterator last, Compare cmp)

{

    g_sort = &cmp;

    typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;

    typedef typename iterator_traits<RandomAccessIterator>::const_pointer const_pointer;

       

    qsort (first, distance (first, last), sizeof(value_type), &qsort_adapter<const_pointer, Compare>);

    g_sort = NULL;

}

模版函数sort()里面要调用另一个模版函数qsort_adapter();在symbian编译下可能产生编译错误,找不到qsort_adapter()的实例化函数,此种情况在模板类的设计中也产生了问题如下代码

 

template <typename K, typename V, typename Cmp = less<double>>

class map : public vector<pair<K,V> >

 

这个模板类的定义里有一个缺省的值,这个缺省值也是一个模板类,如是的定义在symbian的编译环境下进行编译依然是有问题的,或许是symbian的编译器不够只能,所以我们要把嵌套包含的模板类或者模板函数进行类型重定义(typdef),如下:

 

 

typedef int  (*myfunc)(const void* , const void* );

 

template <typename RandomAccessIterator, typename Compare>

void sort (RandomAccessIterator first, RandomAccessIterator last, Compare cmp)

{

    g_sort = &cmp;

    typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;

    typedef typename iterator_traits<RandomAccessIterator>::const_pointer const_pointer;

   

    myfunc p = &qsort_adapter<const_pointer, Compare>;

   

    qsort (first, distance (first, last), sizeof(value_type),p);

    g_sort = NULL;

}

 

 

typedef less<double> less_vdouble;

template <typename K, typename V, typename Cmp = less_vdouble>

 

这样定义就可以通便编译

 

3、           static全局变量的支持

首先symbian系统对static变量和全局变量是支持的,所有的static的用

symbian模拟器上都可以正常编译及运行,但是在symbian手机上,static全局变量可以正常编译通过,但是运行时就会出现相应的错误(会莫名的程序退出);同过测试已经可以得出,这个异常退出的情况主要出现在,主程序调用静态库函数,这个函数返回一个static变量的指针或者引用时,程序会在symbian手机上出现异常,如下代码:

 

lib库中写一个全局函数,返回一个全局的静态变量的指针,

static int* g_test = new int(200);

 

int* g_func()

    {

        return g_test;

   

    }

 

在链接这个lib库的主程序中调用g_func时,在symbian手机上会异常退出;

 

解决:

把静态全局变量写成局部的静态变量,即上述代码行如下改变

int* g_func()

    {

static int* g_test = new int(200);

 

        return g_test;

   

    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值