智能指针及其实现


智能指针:不需要用户去考虑申请的空间什么时候释放(将可以解决这个问题的指针成为智能指针)


RAII(Resource Acquisition Is Initialization)


RAII(资源分配即初始化)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。 即(定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放


RAII 的一般做法是这样的:在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
1 . 不需要显式地释放资源。
2 . 采用这种方式,对象所需的资源在其生命期内始终保持有效。


使用 RAII 能够将非内存资源的生命周期管理转为内存资源生命周期的管理,使得我们能够使用管理内存资源的手段来管理非内存资源,例如 auto_ptr,shared_ptr


scope lock (局部锁技术)
在很多时候,为了实现多线程之间的数据同步,我们会使用到 mutex,critical section,event,singal 等技术。但在使用过程中,由于各种原因,有时候,我们会遇到一个问题:由于忘记释放锁,产生死锁现象。采用RAII 就可以很好的解决这个问题,使用着不必担心释放锁的问题。


模拟实现auto_ptr


(C++98)(不建议使用,拷贝完成后当前指针变指向空)

template <class T>
class AutoPtr{
public:
    AutoPtr(T* ptr = NULL)
        :_ptr(ptr)
    {}

    AutoPtr(AutoPtr<T>& s)
        :_ptr(s._ptr){
        s._ptr = NULL;
    }

    AutoPtr<T>& operator= (AutoPtr<T>& s){
        if (this != &s){
            if (_ptr){
                delete _ptr;
            }
            _ptr = s._ptr;
            s._ptr = NULL;
        }
        return *this;
    }

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

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

    ~AutoPtr(){
        if (_ptr){
            delete _ptr;
        }
    }
private:
    T* _ptr;
};

typedef struct student{
    size_t _id;
    int _age;
}S;

void Test(){
    AutoPtr<int> p1(new int);
    AutoPtr<int> p2(p1);
    AutoPtr<int> p3;
    p3 = p2;

    *p3 = 10;
    cout << *p3 << endl;
    AutoPtr<S> p4(new S);

    p4->_id = 9527;
    p4->_age = 20;
    cout << p4->_id << ":" << p4->_age << endl;
}

优化后

template <class T>
class AutoPtr{
public:
    AutoPtr(T* ptr = NULL)
        :_ptr(ptr)
        , _owner(true){
        if (_ptr == NULL){
            _owner = false;
        }
    }

    AutoPtr(const AutoPtr<T>& ap){
        _ptr = ap._ptr;
        _owner = ap._owner;
        ap._owner = false;
    }
    AutoPtr<T>& operator=(const AutoPtr<T>& ap){
        if (this != &ap){
            if (_owner){
                delete _ptr;
            }
            _ptr = ap._ptr;
            _owner = ap._owner;
            ap._owner = false;
        }
        return *this;
    }

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

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

    ~AutoPtr(){
        if (_owner && _ptr){
            delete _ptr;
            _owner = false;
        }
    }
private:
    T* _ptr;
    mutable bool _owner;
};

void Test(){
    AutoPtr<int> p1(new int);
    AutoPtr<int> p2(p1);
    AutoPtr<int> p3;
    p3 = p1;
}

C++智能指针使用的头文件< memroy >


模拟实现scoped_ptr


不能拷贝

template<class T>
class ScopedPtr{
public:
    ScopedPtr(T* p = NULL)
        :_ptr(p)
    {}

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

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

    ~ScopedPtr(){
        if (_ptr){
            delete _ptr;
        }
    }

private://防拷贝 故将拷贝构造和赋值运算符只声明且放在私有条件下
    ScopedPtr(const ScopedPtr<T>& sq);
    ScopedPtr<T>& operator=(const ScopedPtr<T>& sq);
private:
    T* _ptr;
};

scoped_array


(不能拷贝)(boost库中,标准库无,标准库有map)

template <class T>
class ScopedArray{
public:
    ScopedArray(T* array = NULL)
        :_array(array)
    {}

    ~ScopedArray(){
        if (_array){
            delete[] _array;
        }
    }

    T& operator[](size_t index){
        return _array[index];
    }

    const T& operator[](size_t index)const{
        return _array[index];
    }

private:
    ScopedArray(const ScopedArray<T>& array);
    ScopedArray<T>& operator=(const ScopedArray<T> & array);
private:
    T* _array;
};
void Test(){
    ScopedArray<int> sp(new int[10]);
    sp[5] = 10;
    cout << sp[5] << endl;

}

shared_ptr


/***************定制删除器***************/
template <class T>
class Delete{
public:
    void operator()(T* &p){
        if (p){
            delete p;
            p = NULL;
        }
    }
};

template <class T>
class Free{
public:
    void operator()(T* &p){
        if (p){
            free(p);
            p = NULL;
        }
    }
};

class FClose{
public:
    void operator()(FILE* &fp){
        if (fp){
            fclose(fp);
            fp = NULL;
        }
    }
};
/***************** shared_ptr *********************/
template <class T,class DP = Delete<T>>
class SharedPtr{
public:
    SharedPtr(T* p = NULL)
        :_ptr(p)
        ,_pCount(NULL){
        if (_ptr){
            _pCount = new int(1);
        }
    }
    SharedPtr(SharedPtr<T>& sp)
        :_ptr(sp._ptr)
        , _pCount(sp._pCount){
        ++GetRef();
    }

    SharedPtr<T>& operator=(const SharedPtr<T>& sp){
        if (this != &sp){
            Release();
            _ptr = sp._ptr;
            _pCount = sp._pCount;
            ++GetRef();
        }
        return *this;
    }

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

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

    int UseCount(){
        return GetRef();
    }

    ~SharedPtr(){
        Release();
    }
private:
    void Release(){
        if (_ptr && 0 == --*_pCount){
            //DP()(_ptr);//类
            _dp(_ptr);
            delete _pCount;
        }
    }

    int& GetRef(){
        return *_pCount;
    }

private:

    T* _ptr;
    int* _pCount;
    DP _dp;
};

typedef struct Student{
    int _a;
    char _b;
}S;
/******************** 测试 ********************/
void Test2(){
    SharedPtr<int> p1(new int(10));
    SharedPtr<int> p2(p1);
    SharedPtr<int> p3;
    p3 = p1;
    *p1 = 1;
    *p3 = 2;
    cout << *p1 << endl;
    cout << *p2 << endl;
    cout << *p3 << endl;
    cout << "p1:" << p1.UseCount() << endl;
    cout << "p2:" << p1.UseCount() << endl;
    cout << "p3:" << p1.UseCount() << endl;
    SharedPtr<S> p4(new S);
    p4->_a = 10;
    p4->_b = 'a';
    cout << "p4:" << p4->_a << "-" << p4->_b << endl;
    cout << "p4:" << p4.UseCount() << endl;
}

void Test1(){
    SharedPtr<int> p1(new int);
    SharedPtr<char,Free<char>> p2((char*)malloc(sizeof(char)));
    SharedPtr<FILE,FClose> p3(fopen("Input.txt", "r"));
}



shared_ptr——循环引用


这里写图片描述


这里写图片描述


解决方案:使用 weak_ptr


这里写图片描述


weak_ptr


weak_ptr底层实现:相比于shared_ptr,weak_ptr底层没有引用计数,当weak_ptr指向一个空间时,空间的引用计数不会增加,weak_ptr是个具备指针(* ->等)功能的,但其不具备释放空间(不会管理空间,只是操纵)。故称其为弱智能指针。


猜你喜欢

转载自blog.csdn.net/Romantic_C/article/details/81592819