【Qt】std::shared_ptr<>与std::make_shared<>

cpp 复制代码
std::shared_ptr<int>

这是 C++11 引入的:

txt 复制代码
智能指针(Smart Pointer)

完整理解:

txt 复制代码
一个"自动管理 int 对象生命周期"的指针

它属于:

cpp 复制代码
#include <memory>

中的内容。


一、先看传统指针的问题

传统写法:

cpp 复制代码
int* p = new int(10);

这里:

  • new
    → 在堆上申请内存

返回:

txt 复制代码
int*

也就是普通指针。


问题:容易内存泄漏

你必须手动:

cpp 复制代码
delete p;

否则:

txt 复制代码
内存泄漏

例如:

cpp 复制代码
void test()
{
    int* p = new int(10);

    return; // 忘记delete
}

这块内存永远回收不了。


二、shared_ptr 的作用

于是 C++11 提供:

cpp 复制代码
std::shared_ptr

用于:

txt 复制代码
自动释放内存

三、这句代码是什么意思

cpp 复制代码
std::shared_ptr<int> p;

拆开看:


1. shared_ptr

表示:

txt 复制代码
共享所有权智能指针

意思:

txt 复制代码
多个指针可以共同拥有同一个对象

内部使用:

txt 复制代码
引用计数

管理生命周期。


2. <int>

模板参数。

表示:

txt 复制代码
它管理的是 int 类型对象

类似:

cpp 复制代码
std::vector<int>

里的 <int>


3. 整体意思

cpp 复制代码
std::shared_ptr<int> p;

等价理解:

txt 复制代码
定义一个"管理 int 对象"的智能指针

四、最常见正确写法

通常这样创建:

cpp 复制代码
auto p = std::make_shared<int>(10);

意思:

txt 复制代码
在堆上创建 int(10)
并用 shared_ptr 管理

五、内部发生了什么

cpp 复制代码
auto p = std::make_shared<int>(10);

大致等价于:

cpp 复制代码
int* raw = new int(10);

但:

txt 复制代码
shared_ptr 会自动 delete

你不需要:

cpp 复制代码
delete

六、使用方式


读取值

cpp 复制代码
std::cout << *p;

输出:

txt 复制代码
10

因为:

cpp 复制代码
*p

是解引用。


修改值

cpp 复制代码
*p = 20;

七、shared(共享)是什么意思

这是 shared_ptr 最核心部分。


多个 shared_ptr 指向同一对象

cpp 复制代码
auto p1 = std::make_shared<int>(100);

auto p2 = p1;

此时:

txt 复制代码
p1 和 p2
共同拥有同一个 int

内存里:

txt 复制代码
      +--------+
p1 -->| int100 |
p2 -->|        |
      +--------+

八、引用计数

shared_ptr 内部有:

txt 复制代码
引用计数(Reference Count)

创建时

cpp 复制代码
auto p1 = std::make_shared<int>(100);

计数:

txt 复制代码
1

拷贝后

cpp 复制代码
auto p2 = p1;

计数:

txt 复制代码
2

一个对象销毁

cpp 复制代码
p2 离开作用域

计数:

txt 复制代码
1

最后一个销毁

txt 复制代码
计数=0

自动:

cpp 复制代码
delete

释放内存。


九、例子

cpp 复制代码
#include <iostream>
#include <memory>

int main()
{
    auto p1 = std::make_shared<int>(10);

    {
        auto p2 = p1;

        std::cout << p1.use_count() << std::endl;
    }

    std::cout << p1.use_count() << std::endl;
}

输出:

txt 复制代码
2
1

十、为什么推荐 make_shared

推荐:

cpp 复制代码
auto p = std::make_shared<int>(10);

不推荐:

cpp 复制代码
std::shared_ptr<int> p(new int(10));

因为:


make_shared 优点

1. 性能更好

一次内存分配。


2. 更安全

避免异常导致泄漏。


3. 代码更简洁


十二、如何判断为空

cpp 复制代码
if (b)
{
    // 非空
}
else
{
    // 空
}

十三、shared_ptr 内存结构

内部大概:

txt 复制代码
shared_ptr
   │
   ├── 指向对象
   │
   └── 引用计数控制块

例如:

txt 复制代码
+----------------+
| control block  |
| ref_count = 2  |
+----------------+
         |
         v
     +-------+
     | int10 |
     +-------+

十四、shared_ptr 最大问题


循环引用

例如:

cpp 复制代码
class A
{
    shared_ptr<B> b;
};

class B
{
    shared_ptr<A> a;
};

结果:

txt 复制代码
A 引用 B
B 引用 A

引用计数永远不为 0。

导致:

txt 复制代码
内存泄漏

解决方法

使用:

cpp 复制代码
std::weak_ptr

打破循环引用。


十五、智能指针三兄弟


1. unique_ptr

独占所有权。

txt 复制代码
一个对象只能有一个主人

不能复制。

性能最好。


2. shared_ptr

共享所有权。

可多个指针共享。

有引用计数开销。


3. weak_ptr

弱引用。

不增加引用计数。

用于:

  • 观察对象
  • 打破循环引用

十六、现代 C++ 推荐

现代 C++:

txt 复制代码
尽量不要直接 new/delete

推荐:

cpp 复制代码
make_unique
make_shared

RAII 自动管理资源。


十七、Qt 中的对应关系

Qt 里类似:

STL Qt
shared_ptr QSharedPointer
weak_ptr QWeakPointer
unique_ptr QScopedPointer

不过现代 Qt 项目:

很多人直接使用 STL 智能指针。

相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00616 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术16 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript