爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      【C++11】make_shared函数|std::make_unique

      首页 知识中心 软件开发 文章详情页

      【C++11】make_shared函数|std::make_unique

      2025-02-17 09:20:29 阅读次数:12

      make,new,ptr,shared,std,内存,对象

      std::make_shared 和 std::make_unique是什么

      std::shared_ptr 或 std::unique_ptr的区别

      std::make_shared 和 std::make_unique的作用

      std::make_shared 和 std::make_unique的使用

      std::make_shared 和 std::make_unique是什么

      std::make_shared 和 std::make_unique 是 C++ 标准库提供分别用于创建std::shared_ptr和std::unique_ptr智能指针的接口。

      它们都帮助管理动态分配对象的生命周期,确保当没有指向对象的有效指针时,该对象将被自动删除,从而避免内存泄漏。

      std::shared_ptr 或 std::unique_ptr的区别

      std::shared_ptr:

              多个 std::shared_ptr 实例可以指向同一个对象A,既一个std::shared_ptr 指向对象A,别的std::shared_ptr也可以指向对象A,并且对象A将在最后一个引用被销毁或重置时自动释放。

      std::unique_ptr:

              只有一个 std::unique_ptr 实例可以指向给定的对象A,既一个std::unique_ptr 指向对象A后,你不能创建另一个 std::unique_ptr 来同时指向同一个对象 A(也就是‘不可复制但可移动’);但是可以通过移动语义转移所有权。对象 A 将在其唯一的 std::unique_ptr 指针被销毁或重置时自动释放。

      std::make_shared 和 std::make_unique的作用

      作用是:减少分内存配次数

      比直接使用 new 创建 shared_ptr 更高效,因为它只进行一次内存分配(为控制块和对象一起):

      std::shared_ptr<Widget> spw(new Widget);  分配2次内存

      auto spw = std::make_shared<Widget>(); 只分配1次内存

      原理是:

      std::shared_ptr 不仅仅是一个指向动态分配对象的指针;它实际上管理着一个额外的数据结构,通常称为“控制块”(需要内存块)。这个控制块包含了引用计数(用于跟踪有多少个 shared_ptr 实例共享同一个对象)以及其他信息,比如指向实际对象的指针、自定义删除器等。

      当你直接使用 new 来创建一个对象并将其交给 std::shared_ptr 时,会发生两次内存分配:
      1. 第一次是通过 new 分配给实际对象的内存。
      2. 第二次是当 std::shared_ptr 构造函数为控制块分配内存。

      【C++11】make_shared函数|std::make_unique

      如果选择使用 make_shared 的话, 只会发生一次内存分配,这是因为std::make_shared申请一个单独的内存块来同时存放Widget对象和控制块。下面这样:

      【C++11】make_shared函数|std::make_unique

      std::make_shared 和 std::make_unique的使用

      
      shared_ptr<string> p1 = make_shared<string>(10, '9');  
       
      shared_ptr<string> p2 = make_shared<string>("hello");  
       
      shared_ptr<string> p3 = make_shared<string>(); 
      
      #include <memory>
      #include <iostream>
      
      int main() {
          auto sp = std::make_shared<int>(10); // 创建一个指向 int 的 shared_ptr
          std::cout << "Value: " << *sp << ", use count: " << sp.use_count() << '\n';
      }
      
      
      int main() {
          auto up = std::make_unique<int>(20); // 创建一个指向 int 的 unique_ptr
          std::cout << "Value: " << *up << '\n';
      }

      尽量使用make_shared初始化

      C++11 中引入了智能指针, 同时还有一个模板函数 std::make_shared 可以返回一个指定类型的 std::shared_ptr, 那与 std::shared_ptr 的构造函数相比它能给我们带来什么好处呢 ?

      make_shared初始化的优点

      1、提高性能

      shared_ptr 需要维护引用计数的信息:
      强引用, 用来记录当前有多少个存活的 shared_ptrs 正持有该对象. 共享的对象会在最后一个强引用离开的时候销毁( 也可能释放).
      弱引用, 用来记录当前有多少个正在观察该对象的 weak_ptrs. 当最后一个弱引用离开的时候, 共享的内部信息控制块会被销毁和释放 (共享的对象也会被释放, 如果还没有释放的话).
      如果你通过使用原始的 new 表达式分配对象, 然后传递给 shared_ptr (也就是使用 shared_ptr 的构造函数) 的话, shared_ptr 的实现没有办法选择, 而只能单独的分配控制块:

      【C++11】make_shared函数|std::make_unique

       

       

      如果选择使用 make_shared 的话, 情况就会变成下面这样:

      【C++11】make_shared函数|std::make_unique

      std::make_shared(比起直接使用new)的一个特性是能提升效率。使用std::make_shared允许编译器产生更小,更快的代码,产生的代码使用更简洁的数据结构。考虑下面直接使用new的代码:

      std::shared_ptr<Widget> spw(new Widget);
      

      很明显这段代码需要分配内存,但是它实际上要分配两次。每个std::shared_ptr都指向一个控制块,控制块包含被指向对象的引用计数以及其他东西。这个控制块的内存是在std::shared_ptr的构造函数中分配的。因此直接使用new,需要一块内存分配给Widget,还要一块内存分配给控制块。

      如果使用std::make_shared来替换

      auto spw = std::make_shared<Widget>();
      

      一次分配就足够了。这是因为std::make_shared申请一个单独的内存块来同时存放Widget对象和控制块。这个优化减少了程序的静态大小,因为代码只包含一次内存分配的调用,并且这会加快代码的执行速度,因为内存只分配了一次。另外,使用std::make_shared消除了一些控制块需要记录的信息,这样潜在地减少了程序的总内存占用。

      对std::make_shared的效率分析可以同样地应用在std::allocate_shared上,所以std::make_shared的性能优点也可以扩展到这个函数上。

      对std::make_shared的性能分析同样适用于std::allocated_shared,因此std::make_shared的性能优势也同样存在于std::allocated_shared。

      2、 异常安全

      我们在调用processWidget的时候使用computePriority(),并且用new而不是std::make_shared:

      processWidget(std::shared_ptr<Widget>(new Widget),  //潜在的资源泄露 
                    computePriority());
      

      就像注释指示的那样,上面的代码会导致new创造出来的Widget发生泄露。那么到底是怎么泄露的呢?调用代码和被调用函数都用到了std::shared_ptr,并且std::shared_ptr就是被设计来阻止资源泄露的。当最后一个指向这儿的std::shared_ptr消失时,它们会自动销毁它们指向的资源。如果每个人在每个地方都使用std::shared_ptr,那么这段代码是怎么导致资源泄露的呢?

      答案和编译器的翻译有关,编译器把源代码翻译到目标代码,在运行期,函数的参数必须在函数被调用前被估值,所以在调用processWidget时,下面的事情肯定发生在processWidget能开始执行之前:

      表达式“new Widget”必须被估值,也就是,一个Widget必须被创建在堆上。
      std::shared_ptr(负责管理由new创建的指针)的构造函数必须被执行。
      computePriority必须跑完。
      编译器不需要必须产生这样顺序的代码。但“new Widget”必须在std::shared_ptr的构造函数被调用前执行,因为new的结构被用为构造函数的参数,但是computePriority可能在这两个调用前(后,或很奇怪地,中间)被执行。也就是,编译器可能产生出这样顺序的代码:

      执行“new Widget”。
      执行computePriority。
      执行std::shared_ptr的构造函数。
      

      如果这样的代码被产生出来,并且在运行期,computePriority产生了一个异常,则在第一步动态分配的Widget就会泄露了,因为它永远不会被存放到在第三步才开始管理它的std::shared_ptr中。

      使用std::make_shared可以避免这样的问题。调用代码将看起来像这样:

      processWidget(std::make_shared<Widget>(),       //没有资源泄露
                    computePriority());           
      

      在运行期,不管std::make_shared或computePriority哪一个先被调用。如果std::make_shared先被调用,则在computePriority调用前,指向动态分配出来的Widget的原始指针能安全地被存放到被返回的std::shared_ptr中。如果computePriority之后产生一个异常,std::shared_ptr的析构函数将发现它持有的Widget需要被销毁。并且如果computePriority先被调用并产生一个异常,std::make_shared就不会被调用,因此这里就不需要考虑动态分配的Widget了。

      如果使用std::unique_ptr和std::make_unique来替换std::shared_ptr和std::make_shared,事实上,会用到同样的理由。因此,使用std::make_unique代替new就和“使用std::make_shared来写出异常安全的代码”一样重要。

      缺点

      构造函数是保护或私有时,无法使用 make_shared

      make_shared 虽好, 但也存在一些问题, 比如, 当我想要创建的对象没有公有的构造函数时, make_shared 就无法使用了, 当然我们可以使用一些小技巧来解决这个问题, 比如这里 How do I call ::std::make_shared on a class with only protected or private constructors?

      对象的内存可能无法及时回收

      make_shared 只分配一次内存, 这看起来很好. 减少了内存分配的开销. 问题来了, weak_ptr 会保持控制块(强引用, 以及弱引用的信息)的生命周期, 而因此连带着保持了对象分配的内存, 只有最后一个 weak_ptr 离开作用域时, 内存才会被释放. 原本强引用减为 0 时就可以释放的内存, 现在变为了强引用, 若引用都减为 0 时才能释放, 意外的延迟了内存释放的时间. 这对于内存要求高的场景来说, 是一个需要注意的问题.

      std::make_unique 和 std::make_shared是三个make函数中的两个,make函数用来把一个任意参数的集合完美转移给一个构造函数从而生成动态分配内存的对象,并返回一个指向那个对象的灵巧指针。第三个make是std::allocate_shared。它像std::make_shared一样,除了第一个参数是一个分配器对象,用来进行动态内存分配。

      优先使用make函数的第一个原因即使用最简单的构造灵巧指针也能看出来。考虑如下代码:

      auto upw1(std::make_unique<Widget>()); // with make func
      std::unique_ptr<Widget> upw2(new Widget); // without make func
      
      auto spw1(std::make_shared<Widget>()); // with make func
      std::shared_ptr<Widget> spw2(new Widget); // without make func
      
      我标注了基本的区别:

          使用new的版本重复了被创建对象的键入,但是make函数则没有。重复类型违背了软件工程的一个重要原则:应该避免代码重复,代码中的重复会引起编译次数增加,导致目标代码膨胀,最终产生更难以维护的代码,通常会引起代码不一致,而不一致经常导致bug产生。另外,输入两次比输入一次要费力些,谁都想减少敲键盘的负担。

      优先使用make函数的第二个原因是和异常安全有关。假设我们有个函数来根据一些优先级处理一个Widget对象:

          void processWidget(std::shared_ptr<Widget> spw, int priority);
      ……

      见前面的 《2、 异常安全》

      假如我们把std::shared_ptr和std::make_shared替换成std::unique_ptr 和std::make_unique,会发生相同的事情。使用std::make_unique来代替new在写异常安全的代码里是和使用std::make_shared一样重要。

      make函数的参数相对直接使用new来说也更健壮。尽管有如此多的工程特性、异常安全以及效率优势,我们这个条款是“尽量”使用make函数,而没有说排除其他情况。那是因为还有情况不能或者不应该使用make函数。

      比如,make函数都不允许使用定制删除器(见条款18,条款19),但是std::unique_ptr和std::shared_ptr的构造函数都可以给Widget对象一个定制删除器。

          auto widgetDeleter = [](Widget* pw) { … };
      

      直接使用new来构造一个有定制删除器的灵巧指针:

          std::unique_ptr<Widget, decltype(widgetDeleter)>
      upw(new Widget, widgetDeleter);
      
      
          std::shared_ptr<Widget> spw(new Widget, widgetDeleter);
      

      用make函数没法做到这一点。

      make函数的第二个限制是无法从实现中获得句法细节。条款7解释了当创建一个对象时,如果其类型通过std::initializer_list参数列表来重载构造函数的,尽量用大括号来创建对象而不是std::initializer_list构造函数。相反,用圆括号创建对象时,会调用non-std::initializer_list构造函数。make函数完美传递了参数列表到对象的构造函数,但它们在使用圆括号或大括号时,也是如此吗?对某些类型来说,这个问题的答案有很大不同。比如:

          auto upv = std::make_unique<std::vector<int>>(10, 20);
      
      
          auto spv = std::make_shared<std::vector<int>>(10, 20);
      

      结果指针是指向一个10个元素的数组每个元素值是20,还是指向2个元素的数组其值分别是10和20 ?或者无限制?

      好消息是并非无限制的 :两个调用都是构造了10元素的数组,每个元素值都是20。说明在make函数里,转移参数的代码使用了圆括号,而不是大括号。坏消息是,假如你想使用大括号初始化器( braced initializer)来创建自己的指向对象的指针,你必须直接使用new。使用make函数需要能够完美传递一个大括号初始化器的能力,但是,如条款30中所说的,大括号初始化器不能够完美传递。但条款30也给出了一个补救方案:从大括号初始化器根据auto类型推导来创建一个 std::initializer_list对象,然后把auto对象传递给make函数:

          // create std::initializer_list
          auto initList = { 10, 20 };
      
      
          // create std::vector using std::initializer_list ctor
          auto spv = std::make_shared<std::vector<int>>(initList);
      

      对于std::unique_ptr来说,其make函数就只在这两种场景(定制删除器和大括号初始化器)有问题。对于std::shared_pr来说,其make函数的问题会更多一些。这两种都是边缘情况,但是一些开发者就喜欢处理边缘情况,你也许也是其中之一。

      一些类会定义自己的opeator new和operator delete。这表示全局的内存分配和释放函数对该对象不合适。通常情况下,类特定的这两个函数被设计成精确的分配或释放类大小的内存块,比如,类Widget的operator new和operator delete仅仅处理sizeof(Widget)大小的内存块。这两个函数作为定制的分配器(通过std::allocate_shared)和解析器(通过定制解析器),对std::shared_ptr的支持并不是很好的选择。因为std::allocate_shared需要的内存数量并不是动态分配的对象的大小,而是对象的大小加上控制块的大小。因此,对于某些对象,其类有特定的operate new和operator delete,使用make函数去创建并不是很好的选择。

      std::make_shared在尺寸和速度上的优点同直接使用new相比,阻止了std::shared_ptr的控制块作为管理对象在同样的内存块上分配。当对象的引用计数变为0,对象被销毁(析构函数被调)。然而,直到控制块同样也被销毁,它所拥有的内存才被释放,因为两者都在同一块动态分配的内存上。

      我前面提到过,控制块除了引用计数本身还包含了其他一些信息。引用计数记录了有多少std::shared_ptr指针指向控制块。另外控制块中还包含了第二个引用计数,记录了有多少个std::weak_ptr指针指向控制块。这第二个引用计数被称作weak count。当一个std::weak_ptr检查是否过期时(见条款19),它会检查控制块里的引用计数(并不是weak count)。假如引用计数为0(假如被指对象没有std::shared_ptr指向了从而已经被销毁),则过期,否则就没过期。

      只要有std::weak_ptr指向一个控制块(weak count大于0),那控制块就一定存在。只要控制块存在,包含它的内存必定存在。这样通过std::shared_ptr的make函数分配的函数则在最后一个std::shared_ptr和最后一个std::weak_ptr被销毁前不能被释放。

      假如对象类型很大,以至于最后一个std::shared_ptr和最后一个std::weak_ptr的销毁之间的时间不能忽略时,对象的销毁和内存的释放间会有个延迟发生。

              class ReallyBigType { … };
              auto pBigObj =  // create very large
              std::make_shared<ReallyBigType>(); // object via
                                              //  std::make_shared
      
      
      … // create std::shared_ptrs and std::weak_ptrs to
      
      // large object, use them to work with it
      
      … // final std::shared_ptr to object destroyed here,
      
      // but std::weak_ptrs to it remain
      
      … // during this period, memory formerly occupied
      
      // by large object remains allocated
      
      … // final std::weak_ptr to object destroyed here;
      
      // memory for control block and object is released
      

      当直接使用new时,ReallyBigType对象的内存可以在最后一个std::shared_ptr销毁时被释放:

      class ReallyBigType { … };       // as before
      
      
      std::shared_ptr<ReallyBigType> pBigObj(new ReallyBigType);
      
                                                         // create very large
                                                         // object via new
      
      …    // as before, create std::shared_ptrs and
           // std::weak_ptrs to object, use them with it
      
      …    // final std::shared_ptr to object destroyed here,
           // but std::weak_ptrs to it remain;
           // memory for object is deallocated
      
      …    // during this period, only memory for the
           // control block remains allocated
      
      
      …    // final std::weak_ptr to object destroyed here;
           // memory for control block is released
      

      你有没有发现,你处在一个不可能或者不适合用std::make_shared的情况下,你会确保避免之前我们见到的这类异常安全问题。最好的办法是确保你直接用new的时候,立即把new的结果传递给一个灵巧指针的构造函数,别的什么先不做。这样会阻止编译器生成代码,避免在new和灵巧指针的构造函数(会接管new出来的对象)直接产生异常。

      举个例子,考虑一个对processWidget函数(我们之前测试过)的非异常安全的调用,这次我们定义一个定制删除器:

      void processWidget(std::shared_ptr<Widget> spw, // as before
                                                      int priority);
      
      
      void cusDel(Widget *ptr);      // custom
                                     // deleter
      

      这里有个非异常安全的调用:

      processWidget(                                           // as before,
                  std::shared_ptr<Widget>(new Widget, cusDel), // potential
                  computePriority()                            // resource
      );                                                       // leak!
      

      回忆下:假如computePriority函数在new Widget之后,但是在std::shared_ptr的构造函数之前被调用,如果computePriority抛了异常,那么动态分配的Widget会被泄露。

      这里因为使用了定制删除器,所以不能使用std::make_shared,这里避免问题的方法是把Widget分配内存和构造std::shared_ptr放置到自己的语句中,然后再用std::shared_ptr去调用processWidget。这是这个技巧的本质,当然我们后面会看到我们可以提升其性能:

      std::shared_ptr<Widget> spw(new Widget, cusDel);
      
      
      processWidget(spw, computePriority()); // correct, but not
                                             // optimal; see below
      

      因为std::shared_ptr拥有从构造函数传递给它的原始指针,即使在构造函数产生异常时,所以上述代码运行正常。在这个例子中,如果spw的构造函数抛异常(比如因为不能够为控制块分配到动态内存),它仍然会保证调用cusDel去析构new Widget返回的结果。

      不同之处在于,我们在非异常安全的代码里给processWidget传递了一个右值。

      processWidget(
          std::shared_ptr<Widget>(new Widget, cusDel), // arg is rvalue
           computePriority()
      );
      

      而在异常安全的调用中,我们传递了一个左值

      processWidget(spw, computePriority()); // arg is lvalue
      

      因为processWidget的std::shared_ptr参数是通过传值的,从一个右值去构造仅仅需要一个move,而从左值去构造需要一个拷贝。对std::shared_ptr来说,这个区别很重要,因为拷贝一个std::shared_ptr需要对其引用计数进行加1的原子操作,而移动一个std::shared_ptr根本不需要对引用计数进行操作。对于这段异常安全的代码如果要达到非异常安全的代码的性能,我们在spw上应用std::move,而把它转化成一个右值(见条款23):

      processWidget(std::move(spw),               // both efficient and
                              computePriority()); // exception safe
      

      这个很有趣,也应该知道。但是同时也无关紧要。因为你应该很少有理由不直接使用make函数。除非你有特别的理由不去用它,否则你应该使用make函数来完成你要做的。

      需要记住的事情:

      1.同直接使用new相比,make函数减小了代码重复,提高了异常安全,并且对于std::make_shared和std::allcoated_shared,生成的代码会更小更快。

      2.不能使用make函数的情况包括我们需要定制删除器和期望直接传递大括号初始化器。

      3.对于std::shared_ptr,额外的不建议使用make函数的情况包括:

      (1)定制内存管理的类,

      (2)关注内存的系统,非常大的对象,以及生存期比 std::shared_ptr长的std::weak_ptr。

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.csdn.net/bandaoyu/article/details/112197053,作者:bandaoyu,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:【C++动态规划 最长公共子序列】1035. 不相交的线|1805

      下一篇:C++算法:2612最少翻转操作数

      相关文章

      2025-05-19 09:04:44

      js小题2:构造函数介绍与普通函数对比

      js小题2:构造函数介绍与普通函数对比

      2025-05-19 09:04:44
      new , 关键字 , 函数 , 对象 , 构造函数
      2025-05-19 09:04:22

      外设驱动库开发笔记54:外设库驱动设计改进的思考

      外设驱动库开发笔记54:外设库驱动设计改进的思考

      2025-05-19 09:04:22
      使用 , 函数 , 初始化 , 定义 , 对象
      2025-05-19 09:04:22

      winform关于catch Program.Main

      winform关于catch Program.Main

      2025-05-19 09:04:22
      catch , new , System , void
      2025-05-19 09:04:22

      外设驱动库开发笔记46:MAX31855热偶变送器驱动

      外设驱动库开发笔记46:MAX31855热偶变送器驱动

      2025-05-19 09:04:22
      对象 , 温度
      2025-05-16 09:15:24

      jQuery遍历对象、数组、集合

      jQuery遍历对象、数组、集合

      2025-05-16 09:15:24
      jQuery , 对象 , 数组 , 遍历 , 集合
      2025-05-14 10:33:31

      计算机初级选手的成长历程——操作符详解(2)

      计算机初级选手的成长历程——操作符详解(2)

      2025-05-14 10:33:31
      对象 , 操作 , 操作符 , 表达式 , 运算 , 逗号 , 逻辑
      2025-05-14 10:33:31

      计算机小白的成长历程——数组(1)

      计算机小白的成长历程——数组(1)

      2025-05-14 10:33:31
      strlen , 个数 , 元素 , 内存 , 十六进制 , 地址 , 数组
      2025-05-14 10:33:25

      超级好用的C++实用库之环形内存池

      环形内存池是一种高效的内存管理技术,特别适合于高并发、实时性要求高的系统中,比如:网络服务器、游戏引擎、实时音视频等领域。

      2025-05-14 10:33:25
      buffer , CHP , 内存 , 分配 , 加锁
      2025-05-14 10:33:16

      30天拿下Python之使用Json

      Json的英文全称为JavaScript Object Notation,中文为JavaScript对象表示法,是一种存储和交换文本信息的语法,类似XML。Json作为轻量级的文本数据交换格式,比XML更小、更快,更易解析,也更易于阅读和编写。

      2025-05-14 10:33:16
      json , Json , Python , 字符串 , 对象 , 序列化 , 转换
      2025-05-14 10:33:16

      C++ 11新特性之unique_ptr

      在C++ 11标准中,智能指针作为一种强大的资源管理工具被引入,极大地提升了代码的健壮性和安全性。其中,std::unique_ptr作为唯一所有权智能指针,以其独特的非拷贝特性及自动内存释放机制,成为现代C++编程中的重要组件。

      2025-05-14 10:33:16
      ptr , std , unique , 指向 , 指针 , 赋值
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5241234

      查看更多

      最新文章

      外设驱动库开发笔记54:外设库驱动设计改进的思考

      2025-05-19 09:04:22

      外设驱动库开发笔记46:MAX31855热偶变送器驱动

      2025-05-19 09:04:22

      超级好用的C++实用库之环形内存池

      2025-05-14 10:33:25

      30天拿下Python之使用Json

      2025-05-14 10:33:16

      C++ 11新特性之unique_ptr

      2025-05-14 10:33:16

      C++ 11新特性之tuple

      2025-05-14 10:33:16

      查看更多

      热门文章

      游戏编程之十一 图像页CPICPAGE介绍

      2022-11-28 01:25:04

      C/C++ 动态解密释放ShellCode

      2023-06-19 06:57:29

      Python中查看变量的类型,内存地址,所占字节的大小

      2023-04-25 10:22:01

      游戏编程之十二 资源管理

      2023-02-15 08:38:56

      Linux Command apt 软件包管理

      2023-05-05 09:57:52

      Java学习之方法调用过程图解(理解)

      2023-04-06 06:35:24

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      深入理解Java内存模型:对并发编程的影响

      【C++】智能指针的原理和实现

      JavaScript基础总结三部曲之一

      Java 序列化与反序列化: 数据持久化的技巧

      Java堆栈详解:内存管理与优化

      驱动开发:运用VAD隐藏R3内存思路

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号