C++11中的智能指针与C++98的智能指针设计对比
众所周知,C++11更新了一个重要的feature,那就是智能指针类,由unique_ptr、shared_prt、weak_ptr组成,这为苦逼的C++程序员们带来了不小的好处:终于在某些情况下不用手动管理内存啦!和内存泄漏说拜拜!咦?为什么要说有些情况下呢?因为这智能指针,只是用了引用计数来实现内存的自动管理,而不像java、go语言那么智能,有gc线程进行处理。但总好过没有吧!起码有了智能指针,就会有C++的RAII思想。
但我作为一个嵌入式开发者,很多环境下还在用该死的GCC4.3、4.4编译器,由于C++11的特性得GCC4.6之后才支持,所以无法享受到智能指针的好处。不过没关系,由于C++的开放性,我们便自己创造了引用计数的智能指针,虽然以后必然会被C++11的智能指针所替代,但可以参考一下两者设计上的区别。
先看C++11 std::shared_ptr实现的原理:
shared_ptr中包含int *cnt和void *ptr两个成员变量,其中cnt为引用计数。可以发现这样的好处是,可以在不修改之前写的类,便可以使用智能指针,如:
class my_class
{
public:
my_class(int a)_a(a) {}
virtual ~my_class()
{
printf("my class destruct\n");
}
void print()
{
printf("value:%d\n", _a);
}
private:
int _a;
}
int main(int argc, char **argv)
{
std::shared_prt<my_class> my = std::make_shared<my_class>(123);
my->print();
}
但这么使用有如下几个缺陷:
1、该指针只可使用一个shared_ptr来管理,否则可能出现多次析构的问题;
2、尽量不要使用shared_ptr的get方法获取裸指针;
3、在my_class中需要将this指针传出去,则得继承std::enable_shared_from_this,再使用shared_from_this()方法将this指针包裹后传出去。
以上的几点缺陷,都是因为引用计数是放在shared_ptr类中进行处理与计算,而不是在被管理的类中,所以在使用时,必须要对shared_ptr类进行拷贝处理。
而在我们设计的C++98模式里的智能指针,有一个基类:
class i_ref
{
public:
virtual ~i_ref(){};
/**
* 增加引用
*/
virtual unsigned long add_ref() = 0;
/**
* 释放引用
*/
virtual unsigned long release_ref()= 0;
};
class c_ref
{
public:
virtual ~c_ref(){};
c_ref ()
: m_lRef(0),m_lDel(1)
{
}
virtual unsigned long add_ref()
{
return InterlockedIncrement(&m_lRef);
}
virtual unsigned long release_ref()
{
if(InterlockedDecrement(&m_lRef) == 0 )
if(InterlockedDecrement(&m_lDel) == 0)
{
delete this;
return 0;
}
return m_lRef;
}
public:
volatile long m_lRef;
volatile long m_lDel;
};
template<class T>
class ref_obj
{
public:
typedef T _PtrClass;
ref_obj()
{
p=0;
}
ref_obj(T* lp)
{
if ((p = lp) != 0)
p->AddRef();
}
ref_obj(const ref_obj<T>& lp)
{
if ((p = lp.p) != 0)
p->AddRef();
}
~ref_obj()
{
if (p)
p->Release();
}
operator T*() const
{
return p;
}
T& operator*() const
{
return *p;
}
/*T** operator&()
{
return &p;
}*/
T* operator->() const
{
return p;
}
T* operator=(T* lp)
{
if (lp != 0)
lp->AddRef();
if (p)
p->Release();
p = lp;
return p;
}
T* operator=(const ref_obj<T>& lp)
{
if (lp != 0)
lp->AddRef();
if (p)
p->Release();
p = lp;
return p;
}
bool operator!() const
{
return (p == 0);
}
T*GetObj(){return p;}
const T*GetObj()const{return p;}
T*p;
};
所需要被智能指针管理的类,必须要继承此基类。故此类中的引用计数存在于被管理的类中。
可以想到,这么做的好处是,将指针赋予ref_obj管理后,无需再ref_obj进行拷贝,比如对this指针的拷贝,也不用再像上面那样需要进行处理,例子如下:
class my_class : public c_ref
{
public:
my_class(int a)_a(a) {}
virtual ~my_class()
{
printf("my class destruct\n");
}
void print()
{
printf("value:%d\n", _a);
}
private:
int _a;
}
int main(int argc, char **argv)
{
ref_obj<my_class> my = new my_class(123);
my->print();
}
但坏处也显而易见,所管理的类必须要继承c_ref类,不如shared_ptr灵活。
两者各有好处,但既然C++11中已将boost的shared_ptr纳入标准,那以后写代码,在C++11的环境下,最好还是用标准中的智能指针方法。