61、智能指针类模板

1、智能指针

  • 智能指针的意义
    — 现代C++开发库中最重要的类模板之一
    — C++中自动内存管理的主要手段
    — 能在很大程度上避开内存相关的问题
  • STL中的智能指针 auto_ptr(#include < memory >)
    — 生命周期结束时,销毁指向的内存空间
    — 不能指向堆数组(只能指向对象或者变量)
    — 一片内存空间只属于一个智能指针对象
    — 多个智能指针对象不能指向同一片内存空间

程序1:STL中的智能指针 auto_ptr 的 头文件为 #include < memory >

#include <iostream>
#include <string>
#include <memory>

using namespace std;

class Test
{
private:
	string m_name;
public:
	Test(string name)
	{
		m_name = name;
		cout << "Hello, " << m_name << "." << endl;
	}
	void print()
	{
		cout << m_name << endl;
	}
	~Test()
	{
		cout<< "Goodbye, " << m_name << "." << endl;
	}

};
int main()
{
	auto_ptr<Test>t1(new Test("xiebs_"));
	t1->print();
	cout << t1.get() << endl;

	cout << endl;

	auto_ptr<Test>t2 = t1;
	t2->print();

	cout << endl;

	cout << t1.get() << endl;
	cout << t2.get() << endl;

	return 0;
}

在这里插入图片描述
分析:这个程序可以看出 STL中的智能指针 auto_ptr 的很强大的功能。

首先,就是智能指针指向一个 Test 类及其初始化:auto_ptr<Test>t1(new Test("xiebs_"))

智能指针模板的成员函数还内置一个 get() 函数,可以得到智能指针对象的地址。

生命周期结束时,销毁指向的内存空间。一片内存空间只属于一个智能指针对象。

多个智能指针对象指向同一片内存空间时前面的指针都会被 delete,只最后一个指针指向存空间,这样就避免重复释放的问题。

避免重复释放原理:

Pointer(const Pointer& obj)
{
	mp = obj.mp;
	const_cast<Pointer&>(obj).mp = NULL;
}

Pointer& operator=(Pointer& obj)
{
	if (this != &obj)
	{
		delete mp;
		mp = obj.mp;
		const_cast<Pointer&>(obj).mp = NULL;
	}
	return *this;
}
  • STL 中的其它智能指针
    — shared_ptr
       带有引用计数机制,支持多个指针对象指向同一片内存
    — weak_ptr
       配合shared_ptr 而引入的一种智能指针
    — unique_ptr
       一个指针对象指向一片内存空间,不能拷贝构造和赋值

2、QT中的智能指针

— QPointer
  1、当其指向的对象被销毁时,它会被自动置空
  2、析构时不会自动销毁所指向的对象。
(它的Pointer类里面的析构函数没有delete Pointer类里面成员变量指针指向的Test对象)

#include <QPointer>
#include <QDebug>

class Test:public QObject
{
private:
    QString m_name;
public:
    Test(QString name)
    {
        m_name = name;
        qDebug() << "Hello, " << m_name;
    }
    
    void print()
    {
        qDebug() << "i'm " << m_name;
    }
    
    ~Test()
    {
        qDebug() << "Goodbye " << m_name;
    }
};

int main()
{
    QPointer<Test> t1(new Test("xiebs"));
    QPointer<Test> t2 = t1;
    QPointer<Test> t3 = t1;
    t1->print();
    t2->print();
    t3->print();
    delete t1;

    qDebug() << t1 << endl;
    qDebug() << t2 << endl;
    qDebug() << t3 << endl;
    return 0;
}

在这里插入图片描述
分析:对于QT里面内置的智能指针 QPointer,我们可以看出它可允许多个智能指针指向同一个对象,但是当其指向的对象被销毁时,所有的智能指针会被自动置空。析构时不会自动销毁所指向的对象,我们要手动 delete 内存空间。

— QSharedPointer
  1、引用计数型智能指针
  2、可以被自由的拷贝和赋值
  3、当引用计数为0时才删除指向的对象
  
原理:QSharedPointer这个智能指针指向一个新的对象时,对象对应的引用计数 + 1,当这个指针对象的生命周期结束时,对象所对应的引用计数 -1。如果引用计数为0,就销毁当前对象。
三个智能指针指向一个新的对象时,对象对应的引用计数就是3,当这个指针对象的生命周期结束时,对象所对应的引用计数 从3减到0,于是开始销毁对象,只销毁一次。

#include <QPointer>
#include <QsharedPointer>
#include <QDebug>

class Test:public QObject
{
private:
    QString m_name;
public:
    Test(QString name)
    {
        m_name = name;
        qDebug() << "Hello, " << m_name;
    }
    void print()
    {
        qDebug() << "i'm " << m_name;
    }
    ~Test()
    {
        qDebug() << "Goodbye " << m_name;
    }
};

int main()
{
    QPointer<Test> t1(new Test("xiebs"));
    QPointer<Test> t2 = t1;
    QPointer<Test> t3 = t1;
    t1->print();
    t2->print();
    t3->print();
    delete t1;

    qDebug() << t1;
    qDebug() << t2;
    qDebug() << t3 << endl;

    QSharedPointer<Test>spt(new Test("zzz"));
    QSharedPointer<Test>spt1(spt);
    QSharedPointer<Test>spt2(spt);
    
    spt->print();
    spt1->print();
    spt2->print();

    return 0;
}

在这里插入图片描述
分析:QSharedPointer 这个智能指针模板相比较QPointer 我个人觉得更好用,毕竟他可以自动析构。原理上面讲了,非常巧妙。

  • QT中的其它智能指针
    — QWeakPointer
    — QScopedPointer
    — QScopedArrayPointer
    — QSharedDataPointer
    — QExplicitlySharedDataPointer

3、创建智能指针类模板

SmartPointer.h

#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H
#include <iostream>
using namespace std;

template <typename T>
class SmartPointer
{
    T* mp;
public:
    SmartPointer(T* mp = nullptr);
    SmartPointer(const SmartPointer<T>& obj);
    SmartPointer<T>& operator=(const SmartPointer<T>& obj);
    T* operator->();
    T& operator*();
    T* get();
    virtual ~SmartPointer();
};

template <typename T>
SmartPointer<T>::SmartPointer(T* mp)
{
    this->mp = mp;
    cout << "SmartPointer(T* mp = nullptr);" << endl;
}

template <typename T>
SmartPointer<T>::SmartPointer(const SmartPointer<T>& obj)
{
    mp = obj.mp;
    const_cast<SmartPointer<T>&>(obj).mp = nullptr;
}

template <typename T>
SmartPointer<T>& SmartPointer<T>::operator=(const SmartPointer<T>& obj)
{
    if(this != nullptr)
    {
        delete mp;
        mp = obj.mp;
        const_cast<SmartPointer<T>&>(obj).mp = nullptr;
    }
    return *this;
}

template <typename T>
T* SmartPointer<T>::operator->()
{
    return mp;
}

template <typename T>
T& SmartPointer<T>::operator*()
{
    return *mp;
}

template <typename T>
T* SmartPointer<T>::get()
{
    return mp;
}

template <typename T>
SmartPointer<T>::~SmartPointer()
{
    if(mp != nullptr)
    {
        delete mp;
        cout << "~SmartPointer()" << endl;
    }

}

#endif // SMARTPOINTER_H

main.cpp

#include <iostream>
#include <string>
#include "SmartPointer.h"
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()
{
	SmartPointer<Test> pt(new Test("xiebs"));

	cout << "pt = " << pt.get() << endl;

	pt->print();

	cout << endl;

	SmartPointer<Test> pt1(pt);

	cout << "pt = " << pt.get() << endl;
	cout << "pt1 = " << pt1.get() << endl;

	pt1->print();


	return 0;
}

在这里插入图片描述
分析:当SmartPointer.h 中的第19行代码和第28行代码const_cast<SmartPointer<T>&>(obj).mp = NULL;意味着Pointer 这个类没有指向Test对象,里面mp指针指向为空。它就不用delete mp了。

小结:

  • 智能指针C++中自动内存管理的主要手段
  • 智能指针在各种平台上都有不同的表现形式
  • 智能指针能够尽可能的避开内存相关的问题
  • STL 和 QT 都提供了对智能指针的支持
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基类智能指针转子类智能指针是一种在面向对象编程中常见的操作,用于将指向基类对象的智能指针转换为指向子类对象的智能指针。这种转换通常发生在需要使用子类特有的方法或属性时。 在C++中,可以使用dynamic_pointer_cast函数来进行基类智能指针到子类智能指针的转换。dynamic_pointer_cast是一个模板函数,它接受两个参数:要转换的目标类型和要转换的智能指针。 以下是一个示例代码: ```cpp #include <iostream> #include <memory> class Base { public: virtual void foo() { std::cout << "Base::foo()" << std::endl; } }; class Derived : public Base { public: void foo() override { std::cout << "Derived::foo()" << std::endl; } void bar() { std::cout << "Derived::bar()" << std::endl; } }; int main() { std::shared_ptr<Base> basePtr = std::make_shared<Derived>(); std::shared_ptr<Derived> derivedPtr = std::dynamic_pointer_cast<Derived>(basePtr); if (derivedPtr) { derivedPtr->foo(); derivedPtr->bar(); } else { std::cout << "Failed to cast basePtr to derivedPtr" << std::endl; } return 0; } ``` 在上述示例中,我们创建了一个基类Base和一个派生类Derived。然后,我们使用std::make_shared函数创建了一个指向Derived对象的基类智能指针basePtr。接下来,我们使用dynamic_pointer_cast将basePtr转换为指向Derived对象的智能指针derivedPtr。如果转换成功,我们就可以使用derivedPtr来调用Derived类中的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值