【ChernoC++笔记】智能指针

【44】【Cherno C++】【中字】C++的智能指针

智能指针(Smart pointers)是C++中的一种特殊类型,用于管理动态分配的内存资源。智能指针通过封装指针,并在适当的时机自动释放内存,从而避免内存泄漏和悬空指针等常见问题。

unique_ptr#

❓为什么叫做unique ptr?

unique_ptr不能复制:

如果复制一个unique_ptr,那么将会有两个指针指向同一块内存,其中一个死了就会释放这块内存,此时另一个指针指向了已经被释放的内存。

▶️unique_ptr的使用

*使用智能指针需要#include <memory>

std::unique_ptr<Entity> entity(new Entity);

unique_ptr不支持下面这种隐式构造,因为它的构造函数为explicit,需要显示构造。

// 不存在从 "Entity *" 转换到 "std::unique_ptr<Entity, std::default_delete<Entity>>" 的适当构造函数
std::unique_ptr<Entity> entity = new Entity();

▶️使用std::make_unique保证安全

如果构造函数抛出异常,可能会得到一个空悬指针导致内存泄漏。

// C++14支持make_unique
std::unique_ptr<Entity> entity = std::make_unique<Entity>();

▶️作用域指针,超出作用域时,它就会被销毁

{   
	std::unique_ptr<Entity> entity(new Entity);
} // 离开作用域时,entity指针自动销毁

▶️不能复制unique_ptr

// 无法引用 函数 "std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp> &) [其中 _Tp=Entity, _Dp=std::default_delete<Entity>]" (已声明 所在行数:394,所属文件:"D:\\Programs\\mingw64\\lib\\gcc\\x86_64-w64-mingw32\\8.1.0\\include\\c++\\bits\\unique_ptr.h") -- 它是已删除的函数
std::unique_ptr<Entity> entity(new Entity);
std::unique_ptr<Entity> e0 = entity;

unique_ptr的定义中,删除了拷贝构造函数和拷贝构造符:

// Disable copy from lvalue.
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;

shared_ptr#

▶️shared_ptr一般使用引用计数来实现

跟踪指针有多少个引用,当引用计数达到零,这块被指向的内存就被释放。

▶️使用std::make_shared提高效率

std::shared_ptr<Entity> sharedEntity(new Entity);

shared_ptr需要分配另一块内存(control block),用来存储引用计数。如果先创建一个new Entity,再传递给shared_ptr构造函数,必须做两次分配:先做一次new Entity的分配,然后是control block的分配。使用make_shared可以避免这一问题。

std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();

make_shared 与 new 的区别:

  • new会导致内存碎片化,make_shared则不会。
  • new: 先new后赋值的方式,是先在堆上分配一块内存,然后在堆上再建一个智能指针控制块,这两个东西是不连续的,会造成内存碎片化;
  • make_shared: make_shared的方式是直接在堆上新建一块足够大的内存,其中包含两部分,上面是内存(用来使用),下面是控制块(包含引用计数),然后用T的构造函数去初始化分配的内存。

▶️可以复制shared_ptr

std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
std::shared_ptr<Entity> e0 = sharedEntity;

▶️所有的shared_ptr死亡后,才会释放指向的内存

{
    std::shared_ptr<Entity> e0;
    {
        std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
        e0 = sharedEntity;
    } // 该作用域结束时,sharedEntity销毁,但Entity没有析构,因为e0仍持有对Entity的引用
} // 第二个作用域结束时,Entity才会析构

weak_ptr#

和shared_ptr搭配使用。

weak_ptr在复制shared_ptr时,不会增加引用计数。

{
    std::shared_ptr<Entity> e0;
    {
        std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
		    std::weak_ptr<Entity> weakEntity = sharedEntity;
    } // 该作用域结束时,Entity就已经析构了
}

C++智能指针weak_ptr详解

weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。

借助 weak_ptr 类型指针可以获取 shared_ptr 指针的一些状态信息,比如有多少指向相同的 shared_ptr 指针、通过expired()判断shared_ptr指针指向的堆内存是否已经被释放等等,还可以解决shared_ptr 循环引用的问题。

什么情况下使用智能指针?#

  • 当需要声明一个堆分配的对象,但不希望自己清理/不想显式地管理内存。
  • 尽量使用unique_ptr,因为它的开销较小。
posted @   rthete  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
主题色彩
点击右上角即可分享
微信分享提示