智能指针

一、概述

智能指针是一个类,主要用于管理堆上分配的内存,它将普通的指针封装成一个栈对象。在栈对象的生命周期结束后,会在析构函数中释放申请的内存,防止内存泄漏。
在使用智能指针的时候,需要引入头文件

1、作用:

智能指针是管理一个普通指针,在函数结束时自动释放内存空间,不需要手动释放内存空间。避免申请的内存空间在函数结束时忘记释放,造成的内存泄漏。

2、智能指针类型

1、auto_ptr:

c++98的方案,c++11已经抛弃,采用所有权模式——(一个对象只能对应一个auto_ptr 指针,当拷贝时,会将对象转移到新的指针所持有,之前的指针不再持有)。

void testAutoPtrFunc()
{
    auto_ptr p1 (new string("This is a auto_ptr!"));
    cout << *p1 << endl;

    auto_ptr p2;
    p2 = p1;
    cout << *p2 << endl;

    // cout << *p1 << endl;    //此时再次访问p1会报错
}
2、unique_ptr:

unique_ptr 实现独占式拥有,保证同一时间内只有一个智能指针可以指向该对象。也是采用所有权模式,但它可以避免内存空间泄漏,因为它针对于(new创建的对象,忘记delete)在编译期就会直接报错,不会在运行期埋下隐患。

void testUniquePtrFunc()
{
    unique_ptr p1 (new string("This is a unique_ptr!"));
    cout << *p1 << endl;

    unique_ptr p2;
    // p2 = p1;//编译期直接报错
    p2 = move(p1);//这样才能赋值,所有权转移

    cout << "move p2:" << *p2 << endl;

    p1 = unique_ptr (new string("Assignment new value!"));
    cout << "p1 new value:" << *p1 << endl;
    cout << "p2 new value:" << *p2 << endl;

    unique_ptr p3;
    p3 = unique_ptr (new string("Should assignment value!"));
    cout << *p3 << endl;

}
3、shared_ptr:

shared_ptr 实现共享式拥有模式。多个智能指针可以指向相同的对象,此对象会与其相关资源在最后一个引用被销毁后释放。它使用计数机制来表示资源被几个指针共享。shared_ptr是为了解决auto_ptr在对象所有权上的局限性,使用引用计数的机制来实现共享所有权的智能指针。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁保护。

(1)、成员函数

a)、use_count:返回引用计数的个数;
b)、unique:返回是否是独占所有权(use_count 为1);
c)、swap:交换两个shared_ptr对象;
d)、reset:放弃内部对象的所有权或拥有对象的变更,会引起原有对象的引用计数的减少;
e)、get:返回内部对象(指针),由于已经重载()方法,因此和直接使用对象是一样的。

void testSharedPtrFunc()
{
    string *str = new string("This is String!");

    shared_ptr p1(str);

    shared_ptr p2;
    p2 = p1;

    cout << "p1 use_count:" << p1.use_count() << endl;
    cout << "p2 use_count:" << p2.use_count() << endl;
    cout << "p1 所有权的值:" << p1.unique() << endl;

    string *str3 = new string("This is String three!");

    shared_ptr p3(str3);

    cout << "p1 swap before:" << p1.get() << endl;
    cout << "p3 swap before:" << p3.get() << endl;
    swap(p1, p3);
    cout << "p1 swap after:" << p1.get() << endl;
    cout << "p3 swap after:" << p3.get() << endl;

    cout << "after p1 use_count:" << p1.use_count() << endl;
    cout << "after p2 use_count:" << p2.use_count() << endl;

    cout << "before set value p1:" << p1.get() << endl;
    cout << "before set value p2:" << p2.get() << endl;
    p2 = p1;
    cout << "after set value p1:" << p1.get() << endl;
    cout << "after set value p2:" << p2.get() << endl;

    cout << "after new p1 use_count:" << p1.use_count() << endl;
    cout << "after new p2 use_count:" << p2.use_count() << endl;

    p1.reset();

    cout << "reset p1 use_count:" << p1.use_count() << endl;
    cout << "reset p2 use_count:" << p2.use_count() << endl;
}

4、weak_ptr:

weak_ptr是一种不控制对象生命周期的智能指针(即弱引用,不强持有对象,引用计数不会增加),它指向一个shared_ptr管理的对象。weak_ptr的目的是打破shared_ptr引起的循环引用,导致内存泄漏的问题。因为两个shared_ptr的对象,相互引用了,那么这两个指针的引用计数永远不会为0,从而内存资源也得不到释放,因此就造成了内存泄漏的风险。

(1)、weak_ptr 与 shared_ptr 之间相互转化

由于不能通过weak_ptr直接访问对象的方法,因此需要将它转化为shared_ptr才能访问对象的方法。weak_ptr没有重载*和->,但可以使用lock获取一个可用的shared_ptr对象。weak_ptr支持拷贝或赋值,但不会影响对应的shared_ptr内部对象的引用计数。
注意:weak_ptr在使用前需要检查其合法性(判断是否已经被释放了)。
expired():用于检查所管理的对象是否已经释放,若已释放,则返回true,否则返回false;
use_count():返回与shared_ptr共享的对象的引用计数;
reset():将weak_ptr置空。

class B;
class A
{
public:
    //这样会造成循环引用,导致内存泄漏
    // shared_ptr _pb;
    //使用weak_ptr 弱引用可以打破循环引用,避免内存泄漏
    weak_ptr _pb;

    ~A()
    {
        cout << "A delete \n";
    }
};

class B
{
public:
    shared_ptr _pa;

    ~B()
    {
        cout << "B delete \n";
    }

    void print()
    {
        cout << "This is Print!" << endl;
    }

};
//MARK: -- Test weak_ptr function
void testWeakPtrFunc()
{
    shared_ptr pb(new B());
    shared_ptr pa(new A());

    cout << "pb use_count:" << pb.use_count() << endl;
    cout << "pa use_count:" << pa.use_count() << endl;
    
    pb->_pa = pa;
    pa->_pb = pb;

    cout << "after pb use_count:" << pb.use_count() << endl;
    cout << "after pa use_count:" << pa.use_count() << endl;

    //weak_ptr 访问对象的方法
    //先检查weak_ptr的合法性
    if (!pa->_pb.expired())
    {
        // pa->_pb->print();   //编译报错

        shared_ptr tmpP = pa->_pb.lock();
        tmpP->print();
    }
}
5、shared_ptr 和 weak_ptr的实现原理:
/*
    shared_ptr 和 weak_ptr的实现原理
*/
//MARK: -- Counter 简单实现
class Counter
{
public:
    Counter() : s(0), w(0){};
    int s;   //shared_ptr 的引用计数
    int w;   //weak_ptr 的引用计数
};

//MARK: -- shared_ptr 的简单实现
template 
class WeakPtr;   //为了用weak_ptr的lock(), 来生成shared_ptr使用,需要拷贝构造

template 
class SharedPtr
{
public:
    SharedPtr(T *p = 0) : _ptr(p)
    {
        cnt = new Counter();

        if (p)
        {
            cnt->s = 1;
        }

        cout << "In construct" << cnt->s << endl;
    }

    ~SharedPtr()
    {
        release();
    }

    SharedPtr(SharedPtr const &s)
    {
        cout << "In s copy con" << endl;
        _ptr = s._ptr;
        s.cnt->s++;
        cout << "Copy s construct" << s.cnt->s << endl;

        cnt = s.cnt;
    }

    SharedPtr(WeakPtr const &w)
    {
        cout << "In w copy con" << endl;
        _ptr = w._ptr;
        w.cnt->s++;
        cout << "Copy w construct" << w.cnt->s << endl;

        cnt = w.cnt;
    }

    SharedPtr &operator=(SharedPtr &s)
    {
        if (this != &s)
        {
            release();
            s.cnt->s++;
            cout << "assign construct" << s.cnt->s << endl;
            cnt = s.cnt;
            _ptr = s._ptr;
        }

        return *this;
    }

    T &operator*()
    {
        return *_ptr;
    }

    T &operator->()
    {
        return _ptr;
    }

    friend class WeakPtr;   //方便weak_ptr 与 shared_ptr设置引用计数和赋值

protected:
    void release()
    {
        cnt->s--;
        cout << "Release" << cnt->s << endl;
        if (cnt->s < 1)
        {
            delete _ptr;
            if (cnt->w < 1)
            {
                delete cnt;
                cnt = nullptr;
            }
        }
    }

private:
    T *_ptr;
    Counter *cnt;
};

//MARK: -- weak_ptr 简单实现
template 
class WeakPtr
{
public:
    WeakPtr()
    {
        _ptr = 0;
        cnt = 0;
    }

    WeakPtr(SharedPtr &s) : _ptr(s._ptr), cnt(s.cnt)
    {
        cout << "w con s" << endl;
        cnt->w++;
    }

    ~WeakPtr()
    {
        release();
    }

    WeakPtr &operator = (WeakPtr &w)
    {
        if (this != &w)
        {
            release();
            cnt = w.cnt;
            cnt->w++;
            _ptr = w._ptr;
        }

        return *this;
    }

    WeakPtr &operator = (SharedPtr &s)
    {
        cout << "w = s" << endl;
        release();
        cnt = s.cnt;
        cnt->w++;
        _ptr = w._ptr;

        return *this;
    }

    SharedPtr lock()
    {
        return SharedPtr(*this);
    }

    bool expired()
    {
        if (cnt)
        {
            if (cnt->s > 0)
            {
                cout << "empty!" << cnt->s << endl;
                return false;
            }
        }

        return true;
    }

//方便weak_ptr与share_ptr设置引用计数和赋值
    friend class SharedPtr;

protected:
    void release()
    {
        if (cnt)
        {
            cnt->w--;
            cout << "WeakPtr release" << cnt->w << endl;
            if (cnt->w < 1 && cnt->s < 1)
            {
                cnt = nullptr;
            }
        }
    }

private:
    T *_ptr;
    Counter *cnt;
};

参考文献:

https://www.cnblogs.com/WindSun/p/11444429.html

你可能感兴趣的:(智能指针)