c++智能指针

       在c++中,动态内存管理是通过运算符new来开辟空间的,然后用delete来释放这个空间。

       动态内存很容易出现问题,因为确保在正确的时间释放内存是很困难的。有时我们会忘记释放内存,这样就会造成内存泄露;有时在还有指针引用内存的时候就释放了它,这时就会出现引用非法内存的指针。

举个例子:

void Test ()
{
int* p1 = new int(1);
bool isEnd = true;
//...
if (isEnd )
{
delete p1 ;
return;
}
//...
delete p1;
}
如果在1f判断中我们忘记delete  p1  ,直接return,那么这块内存就没有释放,很容易造成内存泄露。

所以我们需要使用智能指针来管理动态对象。

所谓智能指针就是智能/自动化的管理指针所指向的动态资源的释放。

STL--auto_ptr

Boost库的智能指针(ps:新的C++11标准中已经引入了
unique_ptr/shared_ptr/weak_ptr

下面我们分别来看一下这几个智能指针:

1)scoped_ptr:


这是比较简单的一种智能指针,正如其名字所述,scoped_ptr所指向的对象在作用域之外会自动得到析构,scoped_ptr是non-copyable的,也就是说你不能去尝试复制一个scoped_ptr的内容到另外一个scoped_ptr中,这也是为了防止错误的多次析构同一个指针所指向的对象。顾名思义,守卫的指针,思想就是防拷贝,在大多时候用不到拷贝构造和赋值运算符重载,那么我们做的就是写出构造函数和析构函数,拷贝构造和赋值运算符重载只声明不定义。

template<class T>
class ScopedPtr
{
public:
    ScopedPtr(T* ptr)
        :_ptr(ptr)
    {}
 
     ScopedPtr()
        :_ptr(NULL)
    {}
 
    ~ScopedPtr()
    {
        if (_ptr)
        {
            delete _ptr;
            _ptr = NULL;
        }
    }
 
    T& operator*()
    {
        return *_ptr;
    }
 
    T* GetPtr()
    {
        return _ptr;
    }
 
protected:
    ScopedPtr<T>(const ScopedPtr<T>& p);
    ScopedPtr<T>& operator = (const ScopedPtr<T>& p);
 
private:
    T* _ptr;
};
 
void Test()
{
    ScopedPtr<int> p1(new int(2));
    ScopedPtr<int> p2=p1;
    ScopedPtr<int> p3(new int(3));
    p3 = p1;
}
 
int main()
{
    Test();
    system("pause");
    return 0;
}
2)shared_ptr:

shared_ptr是一个最像指针的"智能指针".
 shared_ptr与scoped_ptr一样包装了new操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针,可以被自由的拷贝和赋值,在任意的地方共享它,当没有代码使用(引用计数为0)它时才能删除被包装的动态分配的对象。shared_ptr也可以安全地放到标准容器中,并弥补了auto_ptr因为转移语义而不能把指针做为STL容器元素的缺陷。

下面我们来实现以下这个智能指针。

#pragma once
template<class T>
class Sharedptr
{
public:
    Sharedptr()
        :_ptr(NULL)
        , _pcount(new int(1))
    {}
    Sharedptr(T *ptr)
        :_ptr(ptr)
        , _pcount(new int(1))
    {}
    Sharedptr(const Sharedptr<T>& sp)
        :_ptr(sp._ptr)
        , _pcount(sp._pcount)
    {
        ++(*_pcount);
    }
    ~Sharedptr()
    {
        if (_ptr)
        {
            if (--(*_pcount)==0)
            {
                delete _ptr;
                delete _pcount;
                _ptr = NULL;
                _pcount = NULL;
            }
            _ptr = NULL;
        }
    }
    Sharedptr<T>& operator=(const Sharedptr<T> &sp)
    {
        if (this != &sp)
        {
            if (--(*_pcount) == 0)
            {
                delete _ptr;
                delete _pcount;
                _ptr = NULL;
                _pcount = NULL;
            }
            _ptr = sp._ptr;
            _pcount = sp._pcount;
            ++(*_pcount);
        }
        return *this;
    }
private:
    T* _ptr;
    int *_pcount;
};
void test()
{
    int *a = new int(5);
    Sharedptr<int> ap1(a);
    Sharedptr<int> ap2(ap1);
    Sharedptr<int> ap3;
    ap3 = ap2;
}
int main()
{
	test();
	system("pause");
	return 0;
}

2)auto_ptr:

auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者。当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有的动态内存自动释放。即使发生异常,通过异常的栈展开过程也能将动态内存释放。auto_ptr不支持new 数组。

但是它有缺陷,STL容器在分配内存的时候,必须要能够拷贝构造容器的元素。而且拷贝构造的时候,不能修改原来元素的值。而auto_ptr在拷贝构造的时候,一定会修改元素的值。所以STL元素不能使用auto_ptr。

所以最好不要使用。

下面是代码实现:

template<class T>
class Autoptr
{
public:
    
    Autoptr(T *ptr)
        :_ptr(ptr)
    {}
	Autoptr()
        :_ptr(NULL)
    {}
    Autoptr<T>(Autoptr<T>& a)
        :_ptr(a._ptr)
    {
        a._ptr = NULL;
    }
    ~Autoptr()
    {
        if (_ptr)
        {
            delete _ptr;
            _ptr = NULL;
        }
    }
    Autoptr<T>& operator=(Autoptr<T>&a)
    {
        if (this != &a)
        {
            delete _ptr;
            _ptr = a._ptr;
            a._ptr = NULL;
        }
        return *this;
    }
    T& operator*()
    {
        return *_ptr;
    }
    T* Getptr()
    {
        return _ptr;
    }
 
protected:
    T *_ptr;
};
void test()
{
    Autoptr<int> ap0(new int(5));
<span style="white-space:pre">	</span>Autoptr<int> ap1(ap0);
<span style="white-space:pre">	</span>cout << *ap1 << endl;
    Autoptr<int> ap2(ap1);
    cout << *ap2 << endl;
    Autoptr<int> ap3;
    ap3 = ap2;
    cout << *ap3 << endl;
}

int main()
{
	test();
	return 0;
}

希望对大家有所帮助。

最后总结一下:

1、在可以使用 boost 库时,不要使用 std::auto_ptr,因为其不仅不符合 C++ 编程思想,而且极容易出错。

2、在确定对象无需共享的情况下,使用 boost::scoped_ptr(动态数组使用boost::scoped_array)。

3、在对象需要共享的情况下,使用 boost::shared_ptr(动态数组使用boost::shared_array)。

4、在需要访问 boost::shared_ptr 对象,而又不想改变其引用计数的情况下,使用boost::weak_ptr。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值