细说智能指针

提到指针,咱们就会想到指针的高效,固然,滥用指针也会为咱们带来许多的潜在bug。
提到指针,咱们就会想到内存泄漏。好比,使用指针后忘记释放,长此以往,堆空间就会所有使用完,那么会带来很大的危害。再好比,两个指针指向同一片内存区域,咱们对同一片区域进行了屡次释放,一样会形成内存泄漏。
为了方便你们的理解,咱们先来模拟一下,使用指针却忘记释放带来的危害。首先,咱们要定义一个类。此次,仍是定义女友类吧(以前写过一篇《细说C++的友元》用的就是女友类,此次还用这个吧,方便说明问题,更况且咱们这群码畜怎么会有女友呢,没有女友只能本身建立了,哈哈哈哈)。
女生都喜欢自拍,尤为是漂亮的女生。因此,女生会有不少照片,对吧。那么,咱们建立的这个女友类,就让她有照片吧。固然了,你女友的照片确定不会随便给别人的吧,因此要把picutre这个变量声明为private类型。既然,女生喜欢自拍,而且发朋友圈,也就是说,其余人虽然得不到她的照片,却能够经过她的朋友圈看到她的自拍,也就意味着咱们能够经过一个public函数访问picture这个变量。那么,咱们如今来写代码。ios

class Girlfriend{
private:
    int pictures;
public:
    Girlfriend ( int i ){
        cout << "Girlfriend ( int i ) " << endl;   /*这句代码是不须要的,
        写在这里只是为了后期可以方便咱们观察
        */
        this->pictures = i;
    }
    int getPic ( void ){
        return this->pictures;
    }
    ~Girlfriend (){
        cout << "~Girlfriend() " << endl;  /*这句代码是不须要的,
        写在这里只是方便咱们观察
        */
    }
};

接着,咱们来写一个主函数,来使用这个女友类。ide

int main ( int argc, char** argv ){
    Girlfriend* Alice = new Girlfriend( 100 );
    cout << "my girlfriend's pictures are " << mp->getPic() << endl;
    system ( "pause" );
    return 0;
}

运行结果:
细说智能指针
咱们在主函数中作了什么事情呢?咱们经过指针动态建立了一个对象,而且,我建立的这个女友Alice有100张照片。看到这里,不少人就会想,指针危险吗?好像没什么危险啊。不是使用正常吗,看到程序运行结果,程序不是完美的执行了嘛,好像也没什么。
首先,咱们建立的这个指针Alice没有去释放,仅仅建立了一个,危害不大,可是多了以后呢。那好比,咱们如今再来写一个主函数。函数

int main ( int argc, char** argv ){
    Girlfriend* Alice = new Girlfriend( 100 );
    Girlfriend* Lisa = new Girlfriend( 200 );

    cout << "my girlfriend Alice's pictures are " << Alice->getPic() << endl;
    cout << "my girlfriend Lisa's pictures are " << Lisa->getPic() << endl;
    system ( "pause" );
    return 0;
}

运行结果:
细说智能指针
咱们先抛开指针不谈。咱们就来谈谈女友。假如Alice是你女友,你手机里有她的100张照片,后来大家由于一些事情产生了矛盾分手了,因而你交了另一个女友Lisa。有一次,Lisa翻你的手机,发现你居然有100张前女朋友照片,她什么感觉,估计要疯了,你说后果严不严重,因此,趁你的现女朋友没发现以前,赶忙把前女朋友照片给删了,赶忙把前女朋友照片释放掉,否则,后果……
如今,回归正题,咱们使用指针建立对象,一个,两个,都没问题,那若是多了呢?100个,1000个,10000个,那内存还能受的了吗?因此,用完指针以后必定要释放指针。
可是,咱们是人啊,不是机器,总会有遗忘的时候,那么咱们有没有办法在指针使用完毕后,它本身释放呢?当有了这个需求后,咱们就要开始思考解决办法了。很快,咱们就有了解决方案:经过类对象模拟指针。指针有两个运算符,一个是->,另外一个是星号,只要在类内重载这两个操做符就好了。那么,这个类的成员变量是什么呢?就是一个指针。经过类来模拟指针的,这就是智能指针了。如今,咱们先来写一个简陋版的。测试

class SmartPointer{
private:
    Girlfriend* sp;
public:
    SmartPointer ( Girlfriend* p = NULL ){
        sp = p;
    }
    Girlfriend* operator -> (){
        return sp;
    }
    Girlfriend& operator * (){
        return *sp;
    }
    ~SmartPointer (){
        delete sp;
        cout << "~SmartPointer() " << endl;  /*这句代码彻底不必,
        写在这里只是便于咱们观察    
        */
    }
}

咱们在这个智能指针类中,重载指针了指针的两个运算符。经过这样作,咱们解决了使用完毕指针后自动释放的问题。那么,还有一个问题,若是两个指针指向同一片区域,这样在释放指针时也会形成内存泄漏,由于同一片区域被释放两次。这个问题怎么解决呢?经过重载拷贝构造函数和赋值操做符。咱们如今类内实现拷贝构造函数。this

SmartPointer ( const SmartPointer& obj ){
    sp = obj.sp;
    const_cast<SmartPointer&>(obj).sp = NULL;
}

咱们实现了拷贝构造函数,由于同一片区域只能有一个指针指向,因此,咱们在把obj指向的地址赋给sp后,要将obj的sp赋值为NULL。这里用到了一个强制类型转换。
如今,咱们要在类内实现重载赋值操做符。spa

SmartPointer& operator = ( const SmartPointer& obj ){
    if ( this != &obj ){
        delete sp;
        sp = obj.sp;
        obj.sp = NULL;
    }
    return *this;
}

到这里为止,咱们就把智能指针类实现完毕了。同时,使用智能指针还能够避免指针比较或加减运算,由于这些运算会形成指针越界带来的bug。好了,咱们看一下,运行结果,符不符合咱们的预期。
细说智能指针
哇,很是符合。指针使用完毕后完美释放。
下面是完整代码:指针

#include <iostream>
#include <string>
using namespace std;
class Girlfriend{
private:
    int pictures;
public:
    Girlfriend ( int i ){
        this->pictures = i;
        cout << "Girlfriend ( int i )" << endl;
    }
    int getPic ( void ){
        return this->pictures;
    }
    ~Girlfriend (){
        cout << "~Girlfriend ()" << endl;
    }
};

class SmartPointer{
private:
    Girlfriend* sp;
public:
    SmartPointer ( Girlfriend* p = NULL ){
        sp = p;
        cout << "SmartPointer ( Girlfriend* p = NULL )" << endl;
    }
    Girlfriend* operator -> (){
        return sp;
    }
    Girlfriend& operator * (){
        return *sp;
    }
    SmartPointer ( const SmartPointer& obj ){
        sp = obj.sp;
        const_cast<SmartPointer&>(obj).sp = NULL;
    }
    SmartPointer& operator = ( const SmartPointer& obj ){
        if ( this != &obj ){
            delete sp;
            sp = obj.sp;
            const_cast<SmartPointer&>(obj).sp = NULL;
        }
        return *this;
    }
    bool isnull (){
        return ( sp == NULL );
    }
    ~SmartPointer (){
        cout << "~SmartPointer()" << endl;
        delete sp;
    }
};

int main ( int argc, char** argv ){
    SmartPointer Alice = new Girlfriend( 100 );
    SmartPointer Lisa = new Girlfriend( 200 );

    cout << "my girlfriend Alice's pictures are " << Alice->getPic() << endl;
    cout << "my girlfriend Lisa's pictures are " << Lisa->getPic() << endl;

    system ( "pause" );
    return 0;
}

后记:
这篇文章写完也是花了我两个小时了,这其中的代码都是通过我本身电脑测试的。虽然写这篇文章只花了我两个小时,可是,我在写这篇文章以前就已经开始在构思了,该如何写,才能作到通俗易懂。看来真的,想写好一篇文章仍是比较困难的,毕竟要把本身学会的东西,经过语言文字描述出来,仍是不容易的。以前写的一篇《细说C++的友元》上了博客的推荐,这里很是感谢51cto的小编。由于,那篇文章的缘故,我全力以赴的写了这篇文章。
但愿看完的小伙伴可以学到些知识,若是以为我哪里讲解的有误,也能够在评论中指出,或者哪里有不懂的地方,也能够在评论中留言,若是有空,咱们能够探讨下。
同时,感谢51cto的小伙伴们,大佬们花时间耐着性子看完了这篇文章,谢谢,谢谢大家!
最后,固然是但愿,看完的小伙伴们,有所收获后点个赞,表示支持。谢谢!code

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------欢迎打赏!哈哈哈哈!
细说智能指针对象

相关文章
相关标签/搜索