智能指针

2017-08-13  本文已影响0人  狗尾巴草败了

众所周知,在C++11以前,C++的内存释放是众多程序员头疼的问题,这也是导致使用C++开发效率低下的原因之一,为此C++11引入了智能指针这个概念。

原理

智能指针实际上采用引用计数的方法,调用构造函数时,引用计数默认初始化为1,每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。

实现

在C++11中,智能指针采用类模板,该类模板包含了一个引用计数的类。程序员定义的每个类,编译器就会让该类继承引用计数的类。代码实现:

class RefCount {
public:
    RefCount():crefs(0) {}
    virtual ~RefCount() {}
    
    void upCount() {
        ++crefs;
    }
    void downCount() {
        if(--crefs == 0)
            delete this;
    }
    
private:
    int crefs;
};

template<typename T>
class SmartPtr{
public:
    SmartPtr(T* p): ptr(p) {
        ptr->upCount();
    }
    ~SmartPtr() {}
    
    T* operator ->() const {
        return ptr;
    }
    
    T& operator *() const {
        return *ptr;
    }
    
    SmartPtr& operator =(T* p) {
        ptr->downCount();
        p->upCount();
        ptr = p;
        return *this;
    }
    
    SmartPtr(const SmartPtr<T>& p) {
        ptr = p;
        ptr->upCount();
    }
    operator T*() const {
        return ptr;
    }
    
    SmartPtr& operator = (SmartPtr<T>& p) {
        return operator =((T*)p);
    }
private:
    T* ptr;  
};

C++11中的 智能指针

share_ptr 允许多个指针指向同一个对象;
unique_ptr 则单独占有一个对象;
weak_ptr 是一种弱引用, 指向 share_ptr 所管理的对象。

推荐使用make_shared 而不是 new

使用make_shared就能在分配对象的同时将 shared_ptr 与之绑定,从而避免无意中将同一内存绑定到多个独立创建的shared_ptr 上

weak_ptr可以用来解决循环引用

因为 weak_ptr 是弱引用,weak_ptr 的构造和析构不会导致引用计数的增加或者减少
例如:

#include <iostream>
#include <memory>
using namespace std;
class B;
class A {
public:
    shared_ptr<B> pb;
    //weak_ptr<B> pb;
    A() {
        cout << "construct A " << endl;
    }
    ~A() {
        cout << "deconstruct A" << endl;
    }
};
class B {
public:
    shared_ptr<A> pa;
    //weak_ptr<A> pa;
    B() {
        cout << "construct B" << endl;
    }
    ~B() {
        cout << "deconstruct B" << endl;
    }
};
int main() {
    shared_ptr<A> ptrA(new A());
    shared_ptr<B> ptrB(new B());
    cout << ptrA.use_count() << endl;
    cout << ptrB.use_count() << endl;
    ptrA->pb = ptrB;
    ptrB->pa = ptrA;
    cout << ptrA.use_count() << endl;
    cout << ptrB.use_count() << endl;
    return 0;
}

如果使用 share_ptr 在构造函数内,结果将输出

construct A
construct B
1
1
2
2

并没有调用析构函数,导致内存泄漏
如果使用 weak_ptr 在构造函数内,结果将输出

construct A
construct B
1
1
1
1
deconstruct B
deconstruct A

正确调用析构函数,内存被全部释放

上一篇 下一篇

猜你喜欢

热点阅读