智能指针
C++11中的智能指针主要分为3种:std::unique_ptr
、std::shared_ptr
,std::weak_ptr
,存在于头文件 <memory>中。
对于智能指针的创建一般优先建议,分别使用 make_unique
和 make_shared
,而不是使用new
的指针来构建。这种方式创建智能指针有如下几个优点:
- 效率高,避免多次的内存分配。智能指针一般包括:指向资源的指针和引用计数的控制块,使用make的方式可以一次分配对于的内存,避免 make 一次、new 又分配一次。
- 提高了异常安全性,避免出现异常时可能导致的内存泄漏。
一、专有指针:std::unique_ptr
std::unique_ptr
用于独占资源,不允许存在其它的指针也指向相同的资源。因此std::unique_ptr
将不能进行拷贝和赋值,只能进行移动操作。移动std::unique_ptr
后源指针将为null
,所有的资源将会转移到目的指针上。
1、声明构建专有指针的方法如下:
// 声明空指针
unique_ptr<string> up1;
unique_ptr<string> up2(nullptr);
// 推荐写法直接使用 make_unique 来创建智能指针
unique_ptr<string> up0 = make_unique<string>("test");
// 会代码额外开销,进行了两次内存分配操作
unique_ptr<string> up3(new string("test"));
// 不推荐写法
string* pStr = new string("test");
unique_ptr<string> up4(pStr);
// 专有指针不能赋值,只能转移给另一个专有指针
up1 = std::move(up0);
//up2 = up3; // 错误,无法进行赋值操作
2、专有指针作为函数的形参,只能为引用的形式
由于专有指针独占资源,因此其作为形参时如果以值传递的形式出现,将会导致拷贝了另外的指针来指向相同的资源,因此只能以引用的形式存在。如下所示:
// uPtr为专有指针,只能以引用的形式存在
void tmp_fun1(unique_ptr<SmartPoint> &uPtr)
{
string city_u = uPtr->GetCity();
}
二、共享指针:std::shared_ptr
对于共享资源将使用std::shared_ptr
,由多个 std::shared_ptr
实例来共同管理对应的资源,通过引用计数来控制何时将释放该资源,当引用计数为0时,该资源将会被释放。
std::shared_ptr
内部包含两个指针:
- 指向内存对象的指针:相当于原始指针,指向分配的内存对象
- 指向控制块的指针:该指针相对于原始指针,为多出的部分,其指向控制块。控制块中包含引用计数、弱引用计数,以及其它内容。所有
std::shared_ptr
将指向同一个对象,并共用控制块。

1、该指针的构建方式如下所示:
/****** SmartPointer 为自定义类 ******/
// 声明指针
shared_ptr<SmartPointer> sPtr1;
shared_ptr<SmartPointer> sPtr2(nullptr);
// 推荐定义智能指针的方式
shared_ptr<SmartPointer> sPtr3 = make_shared<SmartPointer>(6, "sz02", 88.66);
// 该方式创建指针性能差于make的方式
shared_ptr<SmartPointer> sPtr4(new SmartPointer(6, "sz03", 88.66));
// 不推荐该方法:使用原始指针来构建智能指针
SmartPointer* p1 = new SmartPointer(1, "city01", 10.66);
shared_ptr<SmartPointer> sPtr5(p1);
2、避免给std::shared_ptr
的构造函数传递原始指针
SmartPointer* p1 = new SmartPointer(1, "city01", 10.66);
shared_ptr<SmartPointer> sPtr1(p1);
shared_ptr<SmartPointer> sPtr2(p1);
以上代码中使用原始指针 p1
来作为参数来分别构建智能指针 sPtr1
和sPtr2
,此时sPtr1
和sPtr2
将分别创建对应的控制块,而且各自的控制块中引用计数将为1。当sPtr1
的计数为0时,将释放其指向的内存资源。此时sPtr2
的计数在为0时,又将释放一次指向的资源,但是该资源已经被前面释放了,因此会导致 doble free的情况。
对于必须使用 new 的原始指针来构建智能指针的情况,建议直接在智能指针的构造函数中使用 new 。
3、引用计数
std::shared_ptr
的引用计数是根据当前有多少指针指向对应的资源来计算的
// 构建两个智能指针,其指向整型数值10
shared_ptr<int> sp1(make_shared<int>(10)); // sp1 指向的控制块中引用计数为1
auto sp2(make_shared<int>(10)); // sp2 指向的控制块中引用计数为1
// 创建指针sp3, 让其也指向sp1的资源
shared_ptr<int> sp3(sp1); // sp1 指向的控制块中引用计数将加1,变成2;sp1和sp3共用一个控制块
三、弱指针:std::weak_ptr
当std::shared_ptr
可能悬空时使用std::weak_ptr
,此时指针所指的对象可能已经被释放了。
std::weak_ptr
一般需要使用std::shared_ptr
来进行初始化,它不是一个独立的智能指针,也不能解引用,它是std::shared_ptr
的增强。它与std::shared_ptr
所指的对象相同,但是std::weak_ptr
不会增加std::shared_ptr
的引用计数。
auto sp1(make_shared<int>(66));
weak_ptr<int> wPtr1(sp1);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!