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

心不动则不痛 提交于 2020-02-25 02:04:18

一、智能指针

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中提供了对智能指针的支持

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!