接下来,我们将分别对 shared_ptr、unique_ptr 以及 weak_ptr 这 3 个智能指针的特性和用法做详细的讲解,本节先介绍 shared_ptr 智能指针。C++ 智能指针底层是采用引用计数的方式实现的。简单的理解,智能指针在申请堆内存空间的同时,会为其配备一个整形值(初始值为 1),每当有新对象使用此堆内存时,该整形值 +1;反之,每当使用此堆内存的对象被释放时,该整形值减 1。当堆空间对应的整形值为 0 时,即表明不再有对象使用它,该堆空间就会被释放掉。
<memory>头文件,并位于 std 命名空间中,因此在使用该类型指针时,程序中应包含如下 2 行代码:
#include <memory> using namespace std;
值得一提的是,和 unique_ptr、weak_ptr 不同之处在于,多个 shared_ptr 智能指针可以共同使用同一块堆内存。并且,由于该类型智能指针在实现上采用的是引用计数机制,即便有一个 shared_ptr 指针放弃了堆内存的“使用权”(引用计数减 1),也不会影响其他指向同一堆内存的 shared_ptr 指针(只有引用计数为 0 时,堆内存才会被自动释放)。注意,第 2 行代码并不是必须的,也可以不添加,则后续在使用 shared_ptr 智能指针时,就需要明确指明
std::。
std::shared_ptr<int> p1; //不传入任何实参 std::shared_ptr<int> p2(nullptr); //传入空指针 nullptr注意,空的 shared_ptr 指针,其初始引用计数为 0,而不是 1。
std::shared_ptr<int> p3(new int(10));由此,我们就成功构建了一个 shared_ptr 智能指针,其指向一块存有 10 这个 int 类型数据的堆内存空间。
std::shared_ptr<int> p3 = std::make_shared<int>(10);以上 2 种方式创建的 p3 是完全相同。
//调用拷贝构造函数 std::shared_ptr<int> p4(p3);//或者 std::shared_ptr<int> p4 = p3; //调用移动构造函数 std::shared_ptr<int> p5(std::move(p4)); //或者 std::shared_ptr<int> p5 = std::move(p4);
如上所示,p3 和 p4 都是 shared_ptr 类型的智能指针,因此可以用 p3 来初始化 p4,由于 p3 是左值,因此会调用拷贝构造函数。需要注意的是,如果 p3 为空智能指针,则 p4 也为空智能指针,其引用计数初始值为 0;反之,则表明 p4 和 p3 指向同一块堆内存,同时该堆空间的引用计数会加 1。有关拷贝构造函数,读者可阅读《C++拷贝构造函数》一节做系统了解;有关移动构造函数,读者可阅读《C++移动构造函数》做详细了解;有关 move() 函数的功能和用法,读者可阅读《C++11 move()》一节。
int* ptr = new int; std::shared_ptr<int> p1(ptr); std::shared_ptr<int> p2(ptr);//错误
//指定 default_delete 作为释放规则
std::shared_ptr<int> p6(new int[10], std::default_delete<int[]>());
//自定义释放规则
void deleteInt(int*p) {
delete []p;
}
//初始化智能指针,并自定义释放规则
std::shared_ptr<int> p7(new int[10], deleteInt);
实际上借助 lambda 表达式,我们还可以像如下这样初始化 p7,它们是完全相同的:
std::shared_ptr<int> p7(new int[10], [](int* p) {delete[]p; });
shared_ptr<T> 模板类还提供有其它一些初始化智能指针的方法,感兴趣的读者可前往讲解 shared_ptr 的官网做系统了解。
| 成员方法名 | 功 能 |
|---|---|
| operator=() | 重载赋值号,使得同一类型的 shared_ptr 智能指针可以相互赋值。 |
| operator*() | 重载 * 号,获取当前 shared_ptr 智能指针对象指向的数据。 |
| operator->() | 重载 -> 号,当智能指针指向的数据类型为自定义的结构体时,通过 -> 运算符可以获取其内部的指定成员。 |
| swap() | 交换 2 个相同类型 shared_ptr 智能指针的内容。 |
| reset() | 当函数没有实参时,该函数会使当前 shared_ptr 所指堆内存的引用计数减 1,同时将当前对象重置为一个空指针;当为函数传递一个新申请的堆内存时,则调用该函数的 shared_ptr 对象会获得该存储空间的所有权,并且引用计数的初始值为 1。 |
| get() | 获得 shared_ptr 对象内部包含的普通指针。 |
| use_count() | 返回同当前 shared_ptr 对象(包括它)指向相同的所有 shared_ptr 对象的数量。 |
| unique() | 判断当前 shared_ptr 对象指向的堆内存,是否不再有其它 shared_ptr 对象再指向它。 |
| operator bool() | 判断当前 shared_ptr 对象是否为空智能指针,如果是空指针,返回 false;反之,返回 true。 |
除此之外,C++11 标准还支持同一类型的 shared_ptr 对象,或者 shared_ptr 和 nullptr 之间,进行 ==,!=,<,<=,>,>= 运算。
#include <iostream>
#include <memory>
using namespace std;
int main()
{
//构建 2 个智能指针
std::shared_ptr<int> p1(new int(10));
std::shared_ptr<int> p2(p1);
//输出 p2 指向的数据
cout << *p2 << endl;
p1.reset();//引用计数减 1,p1为空指针
if (p1) {
cout << "p1 不为空" << endl;
}
else {
cout << "p1 为空" << endl;
}
//以上操作,并不会影响 p2
cout << *p2 << endl;
//判断当前和 p2 同指向的智能指针有多少个
cout << p2.use_count() << endl;
return 0;
}
程序执行结果为:
10
p1 为空
10
1
版权说明:Copyright © 广州松河信息科技有限公司 2005-2025 版权所有 粤ICP备16019765号
广州松河信息科技有限公司 版权所有