通过与 Jira 对比,让您更全面了解 PingCode

  • 首页
  • 需求与产品管理
  • 项目管理
  • 测试与缺陷管理
  • 知识管理
  • 效能度量
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案

25人以下免费

目录

C 构造shared_ptr为什么推荐使用make_shared,而非new

C  构造shared_ptr为什么推荐使用make_shared,而非new

构造shared_ptr时推荐使用make_shared而非直接使用new,主要原因是性能优化、内存连续性、异常安全。使用make_shared可以减少一次内存分配,make_shared会在一个连续的内存块中同时分配控制块和对象本身,而使用new则需要两次内存分配,一次是对象本身,另一次是为shared_ptr的控制块。这样,make_shared不仅减少了内存分配次数、降低了内存碎片化的风险,还可以提高内存访问效率。此外,make_shared也提供更好的异常安全保障,因为它可以避免构造函数抛出异常时导致的资源泄露问题。

性能优化方面,make_shared在性能提升的背后,是由于它在创建对象和其关联的控制块时仅进行一次内存分配。这一优化减少了内存分配的开销,并且由于数据和控制块的内存位置更加靠近,还可能带来缓存层面的性能提升。

一、MAKE_SHARED VS NEW

使用new构造shared_ptr需要分别为对象和控制块分配内存,这不仅增加了内存分配的次数,还可能导致两者在内存上分散,使得CPU缓存的使用效率下降。相比之下,make_shared只有一次分配,它将对象和控制块存放在一起,这样可以提高内存使用的连续性和效率。

二、内存分配优化

当使用make_shared时,系统能够保证对象和其相关的引用计数在内存中是连续存放的。这种连续的内存布局有利于减少内存碎片,并且由于对象和控制数据紧密相邻,可以提高内存读取的局部性,进而提高程序运行效率。

三、异常安全性

从异常安全的角度来看,make_shared也是更佳的选择。当通过new创建对象,并将其传递给shared_ptr构造函数时,如果在new表达式和shared_ptr构造函数之间发生异常,那么已经分配的内存将无法被释放,导致内存泄漏。而make_shared将对象构造和shared_ptr的初始化打包在一起,如果在对象构造期间抛出异常,make_shared可以确保没有内存泄漏。

四、附加好处

make_shared不仅仅提供性能与安全上的优势,它还简化了代码。使用make_shared可以避免直接使用new运算符,使得代码看起来更加简洁,并且减少了错误输入的可能性。这样的代码维护起来也更为简单。

五、内存管理细节

另一方面,make_shared对内存的连续分配也带来了一些副作用。由于控制块和对象本身是连续存储的,所以在对象生命周期结束后,控制块还是会占用内存直到所有shared_ptrweak_ptr都释放了它们的引用。在某些特殊场景下,如果对象占用了大量内存,而控制块相对较小,这可能会导致不必要的内存占用。

六、内存释放策略

另外,关于对象的销毁,make_shared和直接使用new还有所不同。当使用make_shared时,一旦最后一个shared_ptr被销毁,对象和控制块将同时被释放。而当通过new创建的对象,控制块可能在对象销毁后依然存在,直到所有的weak_ptr都失效。这种差异在对象析构和内存回收策略上可能会产生影响。

七、应用场景分析

在许多情况下,make_shared是构造shared_ptr的首选。但在某些情况下,直接使用new可能更加适合。例如,当类的构造函数是私有的或受保护的,无法被make_shared访问时;或者当需要精细控制内存分配策略时,比如使用自定义的内存分配器。

八、结论与建议

尽管make_shared在大多数情况下是构造shared_ptr的最佳实践,但开发者在选择make_shared或直接使用new时应考虑具体情景。为了充分发挥C++智能指针的优势,推荐在不违反其他设计原则的前提下,默认选择make_shared。这样可以确保代码的性能、安全性以及可读性得到优化。不过,在内存敏感或需要特殊权限访问构造函数的情况下,选择new可能更合适。

相关问答FAQs:

为什么推荐使用make_shared来构造shared_ptr,而不使用new?

  1. 什么是shared_ptr?
    shared_ptr是C++中的智能指针,用于管理动态分配的内存资源。它可以自动管理内存的分配和释放,避免常见的内存泄漏和悬挂指针的问题。

  2. make_shared与new有什么区别?
    使用make_shared来构造shared_ptr的主要区别是,make_shared可以一次性完成内存分配和对象构造,而new需要两步操作:先分配内存,再构造对象。这样可以提高效率,并且减少内存碎片化的可能性。

  3. 为什么推荐使用make_shared?
    使用make_shared有以下几个优点:

    • 性能优化: make_shared在内存分配和对象构造上是原子操作,相较于new而言,减少了额外的内存开销和指针管理的开销。
    • 内存管理: make_shared使用一块连续的内存来存储对象和计数器,减少了控制块的内存开销。
    • 异常安全性: 在构造函数中发生异常时,make_shared可以确保内存会被正确释放,避免内存泄漏的风险。

总之,使用make_shared可以提高性能和内存管理,并确保异常安全性,因此在构造shared_ptr时推荐使用make_shared。

相关文章