在 C++ 开发中,我们经常会遇到程序运行中突然崩溃、程序运行所用内存越来越多最终不得不重启等问题,这些问题往往都是内存资源管理不当造成的。C++11 新标准中,增添了 unique_ptr、shared_ptr 以及 weak_ptr 这 3 个智能指针来实现堆内存的自动回收,今天就简单的介绍一下shared_ptr的使用。
C++ 智能指针底层是采用引用计数的方式实现的。智能指针在申请堆内存空间的同时,会为其配备一个整形值(初始值为 1),每当有新对象使用此堆内存时,该整形值 +1;反之,每当使用此堆内存的对象被释放时,该整形值减 1。当堆空间对应的整形值为 0 时,即表明不再有对象使用它,该堆空间就会被释放掉。多个 shared_ptr 智能指针可以共同使用同一块堆内存。并且,由于该类型智能指针在实现上采用的是引用计数机制,即便有一个 shared_ptr 指针放弃了堆内存的“使用权”(引用计数减 1),也不会影响其他指向同一堆内存的 shared_ptr 指针(只有引用计数为 0 时,堆内存才会被自动释放)。
从名字share就可以看出了资源可以被多个指针共享,它使用计数机制来表明资源被几个指针共享。可以通过成员函数use_count()来查看资源的所有者个数。当我们调用release()时,当前指针会释放资源所有权,计数减一。当计数等于0时,资源会被释放。
一、智能指针shared_ptr<T>的初始化
#ifndef SHAREPTR_H #define SHAREPTR_H #include <QObject> #include <QDebug> class SharePtr : public QObject { Q_OBJECT public: explicit SharePtr(QString info, QObject *parent = nullptr); ~SharePtr(); public: QString& get_info(); void set_info(QString info); void print_info(); private: QString m_info; }; #endif // SHAREPTR_H
#include "share_ptr.h" SharePtr::SharePtr(QString info, QObject *parent) : QObject(parent),m_info(info) { QString test = QString("%1被创造").arg(info); qDebug() << test; } SharePtr::~SharePtr() { qDebug() << "SharePtr delete:" << m_info; } QString& SharePtr::get_info() { return m_info; } void SharePtr::set_info(QString info) { m_info = info; } void SharePtr::print_info() { qDebug() << "info:" << m_info; }
#include <QCoreApplication> #include <QDebug> #include "share_ptr.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); /* 通过如下2种方式,可以构造出 shared_ptr<T> 类型的空智能指针 */ std::shared_ptr<SharePtr> p1; /* 不传入任何实参 */ /* 注意,空的shared_ptr指针,其初始引用计数为 0,而不是 1。 */ qDebug() << "p1.count:" << p1.use_count(); std::shared_ptr<SharePtr> p2(nullptr); /* 传入空指针 nullptr */ qDebug() << "p2.count:" << p2.use_count(); /* C++11 标准中提供了 std::make_shared<T> 模板函数,其可以用于初始化 shared_ptr智能指针 */ std::shared_ptr<SharePtr> share_ptr = std::make_shared<SharePtr>("123"); /* 查看资源的所有者个数 */ qDebug() << "share_ptr.count:" << share_ptr.use_count(); share_ptr.get()->print_info(); /* 在构建 shared_ptr智能指针,也可以明确其指向 */ std::shared_ptr<SharePtr> share_ptr1(new SharePtr("456")); qDebug() << "share_ptr1.count:" << share_ptr1.use_count(); share_ptr1.get()->print_info(); return a.exec(); }
打印结果如下:
二、shared_ptr<T> 模板还提供有相应的拷贝构造函数和移动构造函数
#include <QCoreApplication> #include <QDebug> #include "share_ptr.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); /* 调用拷贝构造函数 */ /* p 和 p1 都是 shared_ptr 类型的智能指针,因此可以用 p 来初始化 p1,由于 p3 是左值, *因此会调用拷贝构造函数。需要注意的是,如果 p 为空智能指针,则 p1 也为空智能指针,其引用计数初始值为 0;反之, * 则表明 p 和 p1 指向同一块堆内存,同时该堆空间的引用计数会加 1。 */ std::shared_ptr<SharePtr> p = std::make_shared<SharePtr>("111"); qDebug() << "p.count:" << p.use_count(); std::shared_ptr<SharePtr> p1(p); /* 或者 std::shared_ptr<SharePtr> p1 = p; */ qDebug() << "p1.count:" << p1.use_count(); /* 调用移动构造函数 */ std::shared_ptr<SharePtr> p2(std::move(p1)); /* 或者 std::shared_ptr<SharePtr> p2 = std::move(p1); */ /* 对于 std::move(p1) 来说,该函数会强制将 p1 转换成对应的右值,因此初始化 p2 调用的是移动构造函数。 * 另外和调用拷贝构造函数不同,用 std::move(p1) 初始化 p2,会使得 p2 拥有了 p1 的堆内存,而 p1 则变成了空智能指针*/ qDebug() << "p2.count:" << p2.use_count(); qDebug() << "p1.count:" << p1.use_count(); std::shared_ptr<SharePtr> p3 = std::make_shared<SharePtr>("222"); qDebug() << "p3.count():" << p3.use_count(); std::shared_ptr<SharePtr> p4 = std::make_shared<SharePtr>("333"); qDebug() << "p4.count():" << p4.use_count(); p3 = p4; /* "333"引用计数加1,"222"销毁 */ p3.get()->print_info(); qDebug() << "p3.count():" << p3.use_count(); qDebug() << "p4.count():" << p4.use_count(); p3.reset(); qDebug() << "p3.count():" << p3.use_count(); p4.reset();/* 引用计数为0,此时"333"销毁 */ return a.exec(); }
打印结果如下:
三、自定义智能指针的释放规则
在初始化 shared_ptr 智能指针时,还可以自定义所指堆内存的释放规则,这样当堆内存的引用计数为 0 时,会优先调用我们自定义的释放规则。在某些场景中,自定义释放规则是很有必要的。
比如,对于申请的动态数组来说,shared_ptr 指针默认的释放规则是不支持释放数组的,只能自定义对应的释放规则,才能正确地释放申请的堆内存。
对于申请的动态数组,释放规则可以使用 C++11 标准中提供的 default_delete<T> 模板类,我们也可以自定义释放规则:
#include <QCoreApplication> #include <memory> /* 自定义释放规则 */ void delete_int(int*p) { delete []p; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); /* 指定 default_delete 作为释放规则 */ std::shared_ptr<int> p(new int[10], std::default_delete<int[]>()); /*初始化智能指针,并自定义释放规则 */ std::shared_ptr<int> p1(new int[10], delete_int); return a.exec(); }标签:11,std,p1,C++,info,shared,ptr,指针 From: https://www.cnblogs.com/QingYiShouJiuRen/p/17262616.html