智能指针与循环引用


c++11中引入了之前在boost库中的智能指针,智能指针有三种shared_ptr, weak_ptr, unique_ptr。

引入智能指针的作用是为了保证在出现异常时,也能保证堆内存会被释放掉,如下面代码:

void fun() {
    T *t = new T();
    //do something
    delete t;
    return;
}

在do something的时候,如果出现了异常或者其他原因,导致提前结束离开函数,那么new出来的内存将不会被释放。而使用智能指针管理这块内存时,会通常会在智能指针本身被析构时,正确的释放这个new出来的内存。

其中shared_ptr用于共享某一块内存,shared_ptr维护了一个足够大的引用计数,保证在引用计数归0时正确的释放掉堆中的内存,但是仅仅使用shared_ptr是不够的,如下面的代码:

class B;
class A {
public:
    shared_ptr<B> p;
};

class B {
public:
    shared_ptr<A> p;
};

int main() {
    while (true) {
        shared_ptr<A> pa(new A());
        shared_ptr<B> pb(new B());
        pa->p = pb;
        pb->p = pa;
    }
    return 0;
}

在while循环中,先是在栈中构造了两个智能指针,分别管理两块堆内存,记为A, B。然后两个赋值语句,使得在shared_ptr中,A,B的引用计数均为2,所以在析构掉pa与pb时,他们的引用计数都没能到达0,于是发生了循环引用,于是开始内存泄露,用不了多久内存爆炸程序死掉,运气不好还会死机> , <

 

解决方案也很简单,将类A,B中的一个shared_prt改为weak_ptr即可,weak_ptr不会增加shared_ptr的引用计数,所以在pa,pb中会有一个的引用计数为1,在它析构时,会正确的释放掉内存。

所以shared_ptr是用来共享内存,而weak_ptr是用来避免循环引用的。 使用weak_ptr时需要用lock检查weak_ptr保存的指针是否有效。

 

此外unique_ptr是一种特殊的shared_ptr,它的拷贝构造函数以及拷贝运算符是删除的,这意味着当我们这样初始化一个unique_ptr时,它会独占内存:

unique_ptr up(new T());

我们丢失了原生指针,而且unique_ptr不能复制,当然如果非得作死这么写也是不会报错的:

T *p = new T();

unique_ptr up1(p);

unique_ptr up2(p);

这样两个unique_ptr有了同样的原生指针- -!但是这么写毫无意义。

值得注意的是unique_ptr虽然不支持拷贝,但是是支持移动的,所以它通常这么用:

unique_ptr<int> fun() {
    unique_ptr<int> up(new int(999));
    return up;
}
int main() {
    unique_ptr<int> up = fun();
    return 0;
}

保证指针唯一的情况下,还能传递内存的所有权。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM