前言
程序中使用new从堆(自由存储区)分配内存,等不再需要时,使用delete将其释放,C++引入智能指针auto_ptr,以帮助自动完成该过程。随后的编程体验中往往需要有更精致的机制,基于程序员的编程体验和BOOST库提供的解决方案,C++摒弃了auto_ptr,新增了三种智能指针:unique_ptr、shared_ptr和weak_ptr。
目录
智能指针
unique_ptr
unique_ptr的创建
示例
示例
weak_ptr
weak_ptr的创建
weak_ptr成员函数
示例
参考文献
必须包含头文件
unique_ptr 两个unique_ptr不能指向同一个对象;
shared_ptr 允许多个shared_ptr实例指向同一个对象,通过计数管理;
weak_ptr 辅助类,是一种弱引用,指向shared_ptr所管理的对象。
unique_ptr不共享它所管理的对象(两个unique_ptr不能指向同一个对象),只能移动unique_ptr,即对资源管理权限可以实现转移。这意味着,内存资源所有权可以转移到另一个unique_ptr,并且原始unique_ptr不再拥有此资源。
创建方式:unique_ptr
// 初始化方式1
unique_ptr p1(new string("Ladies and Gentlemen!!"));
// 初始化方式2
unique_ptr p2;
p2.reset(new string("Magic show to start!!"));
[注]C++11中没有make_unique,C++14才有
成员函数名 | 功能 |
operator*() | 获取当前unique_ptr指针指向的数据。 |
operator->() | 重载->号,当智能指针指向的数据类型为自定义的结构体时,通过->运算符可以获取其内部的指定成员。 |
operator =() | 重载了 = 赋值号,从而可以将nullptr或者一个右值unique_ptr指针直接赋值给当前同类型的unique_ptr指针。 |
operator []() | 重载了 [] 算符,当unique_ptr指针指向了一个数组,可以直接通过 [] 获取指定下标位置处的数据。 |
get() | 获取当前unique_ptr指针内部包含的普通指针。 |
get_delecter() | 获取当前unique_ptr指针释放堆内存空间所用的规则。 |
operator bool() | unique_ptr指针可直接作为if语句的判断条件,以判断该指针是否为空,如果为空,则为flase;反之为true。 |
relase() | 释放当前unique_ptr指针对所指堆内存的所有权,但该存储空间不会被销毁。 |
reset(p) | 其中p表示一个普通指针,如果p为nullptr,则当前unique_ptr也变为空指针;反之,则该函数会释放当前unique_ptr指针指向的堆内存(如果有),然后获取p所指堆内存的所有权(p为nullptr)。 |
swap(x) |
交换当前unique_ptr指针和同类型的x指针。 |
#include
#include
#include
using namespace std;
int main()
{
unique_ptr p1(new string);
*p1 = "Ladies and Gentlemen!Magic show to start!";
// p接受p1释放的堆内存
string *p = p1.release();
cout << *p << endl;
// 判断p1是否为空指针
if (p1){
cout << "p1 is not nullptr" << endl;
}
else {
cout << "p1 is nullptr" << endl;
}
unique_ptr p2;
p2.reset(p);
cout << *p2 << endl;
return 0;
}
程序执行结果:
Ladies and Gentlemen!Magic show to start!
p1 is nullptr
Ladies and Gentlemen!Magic show to start!
允许多个指针指向同一个对象,利用计数的方式实现对所管理的对象的所有权分享,即允许多个shared_ptr共同管理一个对象。
推荐第一次创建内存资源时,使用make_shared函数创建shared_ptr。
// 初始化方式1
auto p1 = make_shared("Ladies and Gentlemen!");
// 初始化方式2
shared_ptr p2(new string("Magic show to start!"));
// 初始化方式3
shared_ptr p3(nullptr);
p3 = make_shared("It's show time!");
成员函数名 | 功能 |
operator*() | 获取当前shared_ptr智能指针对象指向的数据。 |
operator->() | 重载->号,当智能指针指向的数据类型为自定义的结构体时,通过->运算符可以获取其内部的指定成员。 |
operator=() | 重载 = 赋值号,使得同一类型的shared_ptr智能指针可以相互赋值。 |
get() | 获取shared_ptr对象内部包含的普通指针。 |
use_count() | 返回同当前shared_ptr对象(包括它)指向相同的所有shared_ptr对象数量。 |
unique() | 判断当前shared_ptr对象指向的堆内存,是否不再有其他shared_ptr对象指向它。 |
operator bool() | 判断当前shared_ptr对象是否为空智能指针,如果是空指针,返回flase;反之,返回true。 |
reset() | 当函数没有实参时,该函数会使当前shared_ptr所指堆内存的引用计数减1,同时将当前对象重置为一个空指针;当为函数传递一个新申请的堆内存时,则调用该函数的shared_ptr对象会获得该存储空间的所有权,并且引用计数的初始值为1。 |
swap() | 交换2个相同类型shared_ptr智能指针的内容 |
除此之外,C++11标准还支持同一类型的shared_ptr对象,或者shared_ptr和nullptr之间,进行==,!=,<,<=,>,>= 运算。
#include
#include
#include
int main()
{
// 构建2个指针
auto p1 = make_shared("Ladies and Gentlemen!It's show time!");
shared_ptr p2(p1);
// 输出p2指向的数据
cout << *p2 << endl;
// 引用计数减1,p1为空指针
p1.reset();
// 判断p1是否为空指针
if (p1){
cout << "p1 is not nullptr" << endl;
}
else {
cout << "p1 is nullptr" << endl;
}
// 以上对p1的操作不会影响p2
cout << *p2 << endl;
// 查看当前与p2同指向的智能指针个数(包括p2)
cout << p2.use_count() << endl;
return 0;
}
程序执行结果:
Ladies and Gentlemen!It's show time!
p1 is nullptr
Ladies and Gentlemen!It's show time!
1
只与shared_ptr指针搭配使用,借助weak_ptr指针,可以获取shared_ptr指针的一些状态信息,如有多少指向相同的shared_ptr指针,shared_ptr指针指向的堆内存是否已被释放等。
通过使用weak_ptr指针,可以创建一个联接到现有相关实例集的shared_ptr,但前提是基础内存资源仍然有效。weak_ptr本身不参与引用计数,因此,它无法阻止引用计数变为0。但是,可以使用weak_ptr尝试获取初始化该副本的shared_ptr的新副本。若已删除内存,则weak_ptr的bool运算符返回false。若内存仍然有效,则新的共享指针会递增引用计数,并保证只要shared_ptr保留再作用域内,内存就会有效。
// 初始化方式1 创建一个空指针
weak_ptr p1;
// 初始化方式2 凭借已有的weak_ptr指针,创建一个新的
// 若p1为空指针,则p2也为空指针;
// 若p1指向某一shared_ptr指针拥有的堆内存,则p2也指向该内存空间(可访问,但无所有权)
weak_ptr p2(p1);
// 初始化方式3 指向某一shared_ptr指针拥有的堆内存
shared_ptr p(new int);
weak_ptr p3(p);
成员函数名 | 功能 |
operator=() | 重载 = 赋值运算符,weak_ptr指针可以直接被weak_ptr或者shared_ptr类型指针赋值。 |
swap(x) | 其中x表示一个同类型的weak_ptr类型指针,该函数可以互换2个共同类型weak_ptr指针的内容。 |
reset() | 将当前weak_ptr指针置为空指针。 |
use_count() | 查看指向和当前weak_ptr指针相同的shared_ptr指针的数量。 |
expired() | 判断当前weak_ptr指针是否过期(指针为空,或者指向的堆内存已经被释放)。 |
lock() | 如果当前weak_ptr已经过期,则该函数会返回一个空的shared_ptr指针;反之,该函数返回一个和当前weak_ptr指针指向相同的shared_ptr指针。 |
值得注意的是,weak_ptr类型指针只能访问某一shared_ptr指针指向的堆内存空间,无法对其进行修改。
#include
#include
#include
int main()
{
shared_ptr sp1(new int(10));
shared_ptr sp2(sp1);
weak_ptr wp(sp2);
// 输出和wp指针指向相同的shared_ptr类型指针数量
cout << wp.use_count() << endl;
// 释放sp2
sp2.reset();
cout << wp.use_count() << endl;
// 借助lock()函数,返回一个和wp同指向的share_ptr类型指针,获取其存储的数据
cout << *(wp.lock()) << endl;
return 0;
}
程序执行结果:
2
1
10
[1]Prata,S.著;张海龙,袁国忠译.C++ Primer Plus中文版:第6版[M].北京:人民邮电出版社,2012.7
[2]智能指针(现代 C++) | Microsoft Docs
[3](11条消息) C++ STL 四种智能指针_恋喵大鲤鱼的博客-CSDN博客_智能指针
[4]如何:创建和使用 unique_ptr 实例 | Microsoft Docs
[5](11条消息) c++11 unique_ptr 与 make_unique源码剖析_私房菜的博客-CSDN博客_make_unique 头文件
[6]C++11 unique_ptr智能指针详解 (biancheng.net)
[7](11条消息) c++11 shared_ptr 与 make_shared源码剖析_私房菜的博客-CSDN博客_make_shared头文件
[8]C++11 shared_ptr智能指针(超级详细) (biancheng.net)