• 第六十一课、智能指针类模板


    一、智能指针

    1、智能指针的意义

    (1)、现代c++开发库中最重要的类模板之一

    (2)、c++中自动内存管理的重要手段

    (3)、能够很大程度上避开内存相关的问题

    2、STL中的只能指针auto_ptr

    (1)、生命周期结束时,销毁指向的内存空间

    (2)、不能指向堆数组(否则发生内存泄漏),只能指向堆对象(变量)

    (3)、一片堆空间只属于一个内存指针对象(防止多次释放)

    (4)、多个只能指针对象不能指向同一片堆空间

    #include <iostream>
    #include <string>
    #include <memory>
    
    using namespace std;
    
    class Test
    {
        string m_name;
    public:
        Test(const char* name)
        {
            cout << "Hello, " << name << "." << endl;
            
            m_name = name;
        }
        
        void print()
        {
            cout << "I'm " << m_name << "." << endl;
        }
        
        ~Test()
        {
            cout << "Goodbye, " << m_name << "." << endl;
        }
    };
    
    int main()
    {
        auto_ptr<Test> pt(new Test("D.T.Software"));
        
        cout << "pt = " << pt.get() << endl;//打印指针的地址
        
        pt->print();
        
        cout << endl;
        
        auto_ptr<Test> pt1(pt);//这句之后发生了所有权的转移,即pt1指向了原来pt指向的内存,而pt=NULL
        
        cout << "pt = " << pt.get() << endl;//0
        cout << "pt1 = " << pt1.get() << endl;//与之前的pt指针一样
        
        pt1->print();
        
        return 0;
    }

    3、STL中的其它智能指针

    (1)、shared_ptr:带有引用计数机制,支持多个指针对象指向同一片内存

    (2)、weak_ptr:配合shared_ptr而引入的一种智能指针

    (3)、unique_ptr一个指针对象指向一片内存,不能拷贝构造和赋值

     二、Qt中的智能指针

    1、QPoiter

    (1)、当其指向的对象被销毁时,它会被自动置空(避免野指针)

    (2)、析构时不会自动销毁所指向的对象(特别注意)

    2、QSharedPoiter

    (1)、引用计数型智能指针

    (2)、可以被自动拷贝和赋值

    (3)、当引用计数为0时才销毁指向的对象

    3、Qt中的其它智能指针

    #include<QPointer>
    #include <QSharedPointer>
    #include <qDebug>
    
    class Test : public QObject
    {
        QString m_name;
    public:
        Test(const char* name)
        {
            m_name = name;
            qDebug() << "Hello, " << m_name << ".";
        }
    
        void print()
        {
            qDebug() << "I'm " << m_name <<".";
        }
    
        ~Test()
        {
            qDebug() << "Good bye, " << m_name <<".";
        }
    };
    
    int main()
    {
        QPointer<Test> pt(new Test("SantaClaus"));//pt= new Test("SantaClaus");
        QPointer<Test> pt1(pt);  //所有权不会转让!与pt指向同一个堆空间
        QPointer<Test> pt2(pt);  //所有权不会转让!与pt指向同一个堆空间
    
        pt->print();
        pt1->print();
        pt2->print();
    
        delete  pt;  //删除对象时,pt、pt1和pt2会同时被置空
                     //注意,pt本身是一个局部对象(而不是指针),但因QPointer<Test>实现了operator Test*()这个类型转换函数(见第42课)
                     //当delete pt时,由于delete要求后面跟一个指针,所以将隐式的把pt对象转为Test*指针类型。因此,删除的是pt
                     //所指的对象,而不是pt本身。
    
    
        qDebug() << "pt = "  << pt;
        qDebug() << "pt1 = " << pt1;
        qDebug() << "pt2 = " << pt2;
    
        qDebug() << endl;
    
        //带有引用计数
        QSharedPointer<Test> spt(new Test("Demo"));
        QSharedPointer<Test> spt1(spt);
        QSharedPointer<Test> spt2(spt);
    
        spt->print();
        spt1->print();
        spt2->print();
    
        return 0;
    }
    
    /*输出结果
    Hello,  "SantaClaus" .
    I'm  "SantaClaus" .
    I'm  "SantaClaus" .
    I'm  "SantaClaus" .
    Good bye,  "SantaClaus" .
    pt =  QObject(0x0)
    pt1 =  QObject(0x0)
    pt2 =  QObject(0x0)
    
    
    Hello,  "Demo" .
    I'm  "Demo" .
    I'm  "Demo" .
    I'm  "Demo" .
    Good bye,  "Demo" .
    */

    三、创建智能指针类模板

    //SmartPoiter.h

    #ifndef _SMARTPOITER_H_
    #define _SMARTPOITER_H_
    template
    <typename T>
    class SmartPoiter
    {
    private:
        T* mp;
    public:
         SmartPoiter(T* p = NULL);
         SmartPoiter(const SmartPoiter<T>& obj);
         SmartPoiter<T>& operator = (const SmartPoiter<T>& obj);
         T* operator -> ();
         T& operator * ();
         T* get();
         ~SmartPoiter();
    };
    
    template
    <typename T>
    SmartPoiter<T>::SmartPoiter(T* p)
    {
        mp =p;
    }   
    
    template
    <typename T>
    SmartPoiter<T>::SmartPoiter(const SmartPoiter<T>& obj)
    {
        mp = obj.mp;
        
        const_cast<SmartPoiter<T>&>(obj).mp = NULL;//转让所有权
    }
    
    template
    <typename T>
    SmartPoiter<T>& SmartPoiter<T>::operator = (const SmartPoiter<T>& obj)//重载赋值操作符的四个注意点
    {
        if(this != &obj)
        {
            delete mp;
            mp = obj.mp;
        
            const_cast<SmartPoiter<T>&>(obj).mp = NULL;//转让所有权
            
        }
        return *this;
    }
    
    template
    <typename T>
    T* SmartPoiter<T>::operator -> ()
         {
            return mp;
         }
         
     template
    <typename T>    
     T& SmartPoiter<T>::operator * ()
     {
        return *mp;
     }    
     
     template
    <typename T>
     T* SmartPoiter<T>::get()
     {
        return mp;
     }
     
     template
    <typename T>
    SmartPoiter<T>::~SmartPoiter()
    {
        delete mp;
    }
    #endif

    //main.cpp

    #include<iostream>
    #include"SmartPoiter.h"
    
    using namespace std;
    
    class Test
    {
        string m_name;
    public:
        Test()
        {
            m_name = "SantaClaus";
            cout <<"Hello, " << m_name << "." << endl;
        }
        Test(const char* name)
        {
            m_name = name;
            cout <<"Hello, " << m_name << "." << endl;
        }
        
        void print()
        {
            cout << "I'm " << m_name << "." << endl;
        }
        
        ~Test()
        {
            cout << "Good bye, " << m_name << "." << endl;
        }
    };
    
    int main()
    {
        SmartPoiter<Test> pt(new Test("D.T.Software"));//本质上还是个对象
        cout << pt.get()<< endl;
        
        SmartPoiter<Test> pt1(pt);//验证拷贝构造函数的所有权转让
        cout << pt.get()<< endl;//0
        cout << pt1.get()<< endl;
       
        SmartPoiter<Test> pt2;
        pt2 = pt1;//验证赋值操作符的所有权转让
        cout << pt1.get()<< endl;//0
        cout << pt2.get()<< endl;
       
        return 0;
    }

    四、小结

    (1)、智能指针是C++中自动内存管理的主要手段

    (2)、智能指针在各种平台上都有不同的表现形式

    (3)、智能指针能够尽可能的避开内存相关的问题

    (4)、STL和Qt中提供了对智能指针的支持

  • 相关阅读:
    第九周学习总结&实验报告(7)
    团队展示
    结对编程
    微信公众号
    编程作业
    《构建之法》
    自我介绍
    java学期总结
    14周作业
    13周总结
  • 原文地址:https://www.cnblogs.com/gui-lin/p/6378110.html
Copyright © 2020-2023  润新知