非常游戏网
make_shared和直接new shared_ptr有什么区别 性能与异常安全对比

make_shared和直接new shared_ptr有什么区别 性能与异常安全对比

2025-08-24日常编程169036

c++++中make_shared比直接new创建shared_ptr更高效且异常安全。1.性能方面:make_shared一次性分配内存用于对象和控制块,减少内存分配次数;而new需两次独立分配,效率较低。2.异常安全方面:使用make_shared时若构造抛出异常不会导致资源泄漏,而new可能引发未释放的原始指针问题。3.建议优先使用make_shared以提升性能与安全性,除非需要自定义删除器或已有原始指针。

在C++中,

make_shared

和直接使用

new

创建

shared_ptr

都可以实现动态内存管理,但它们之间存在显著的差异,尤其是在性能和异常安全方面。


性能对比

使用

make_shared

通常比直接用

new

更高效。这是因为

make_shared

在一次内存分配中同时创建对象和控制块(control block),而直接使用

new

创建

shared_ptr

时,会分别进行两次内存分配:一次用于对象本身,另一次用于控制块。

具体来说:

  • make_shared(args...)

    :一次性分配足够的内存来存放对象和引用计数等信息。

  • shared_ptr(new T(...))

    :需要两次独立的内存分配操作。

由于内存分配是相对耗时的操作,减少分配次数可以带来性能上的提升,特别是在频繁创建对象的场景下。


异常安全对比

在异常安全方面,

make_shared

比直接使用

new

更加安全。考虑以下代码:

foo(make_shared(), make_shared());

在这个例子中,如果编译器先调用两个

make_shared

,再调用

foo

,那么即使其中一个构造函数抛出异常,也不会造成资源泄漏,因为每个

make_shared

是一个完整的表达式。

而如果写成这样:

foo(shared_ptr(new T()), shared_ptr(new U()));

这里涉及了两次独立的

new

操作。如果其中一个构造函数抛出异常(比如

new T()

成功,但

new U()

抛出异常),虽然

shared_ptr

会自动释放它所管理的对象,但由于

new T()

已经执行成功,可能会导致资源泄漏或状态不一致的问题。

因此,在处理可能抛出异常的构造函数时,推荐使用

make_shared

来确保异常安全性。


使用建议与注意事项

如果你希望写出更高效、更安全的代码,可以遵循以下几个建议:

  • 优先使用

    make_shared

    :除非你有特殊需求(例如需要自定义删除器或使用已有的原始指针)。

  • 注意内存模型一致性:当使用

    make_shared

    时,整个对象及其控制块共享同一块内存,这在某些特定场景下可能影响缓存效率。

  • 避免混用不同方式创建的

    shared_ptr

    :尽量保持项目中统一使用

    make_shared

    或手动创建的方式,以减少潜在的复杂性。


基本上就这些。选择合适的方式来创建

shared_ptr

可以帮助你在性能和安全性之间取得更好的平衡。

以上就是make_shared和直接new shared_ptr有什么区别 性能与异常安全对比的详细内容,更多请关注非常游戏网【www.myinqi.com】。

  • 为什么Python 3.11的异常处理几乎零成本_解析Zero-cost Exception
    05月292026

    ExceptionTable是Python3.11+字节码中存储异常跳转元数据的只读表,它用静态查找替代了3.10及以前依赖SETUP_FINALLY/POP_BLOCK等指令的动态块栈操作,使无异常时几乎零开销——仅保留极轻量的间接寻址,而不再执行任何异常相关字节码。 Python3.11的try/except在无异常时确实几乎不耗性能,这不是宣传话术,而是字节码层的结构性改变——Excepti...

  • Python后端Flask如何优化SQL查询性能_使用SQLAlchemy分析N+1问题
    05月292026

    SQLAlchemy中N+1查询源于relationship默认lazy='select',实操应优先用joinedload或selectinload优化,并通过SQL日志、EXPLAIN分析、索引检查及合理session管理来根治。 SQLAlchemy里relationship默认懒加载,一查列表就触发N+1 查10条用户数据,顺带要显示每个用户的最新订单,结果发了11次SQL:1次查用户,再...

  • 为什么Python在生产环境中建议关闭Debug模式_分析性能损耗与安全风险
    05月292026

    生产环境必须关闭debug=True,否则会暴露完整错误堆栈(含绝对路径、变量值、Werkzeug版本)、开放调试器入口(/console)、触发不安全热重载,且无法通过反向代理补救。 生产环境必须关闭debug=True,这不是优化建议,而是安全底线。它直接导致错误堆栈泄露、代码重载失控、内存泄漏加速,且无法通过反向代理或防火墙补救。 Flask的debug=True会暴露什么 开启后,任何未捕...

  • Python 异步编程:结合 asyncio 和 aio-pika 库实现超高性能的 RabbitMQ 异步收发
    05月292026

    直接用aio-pika的connect_robust()会卡住,因其默认等待DNS解析完成,而asyncio对阻塞式DNS处理有缺陷;高并发下channel.declare_queue()报ChannelClosed是因Channel非协程安全,需独占实例或用asyncwith隔离生命周期。 为什么直接用aio-pika的connect_robust()会卡住? 不是连接慢,是它默认等待DNS解析...

  • 如何在Python中优雅地处理文件关闭异常_使用with语句上下文管理器
    05月282026

    with语句确保__exit__执行并调用close(),但close()本身可能抛出异常(如磁盘满、网络断连),且该异常会覆盖原异常;需通过手动close()捕获或finally块处理。 用with语句打开文件,基本不需要手动处理“关闭异常”——因为with本身会确保close()被调用,哪怕发生异常。真正要关注的,是那些close()过程中可能抛出的、被忽略的异常(比如磁盘满、网络文件系统断连...

  • 如何加速Python读取Parquet文件的性能_使用PyArrow后端加载
    05月282026

    PyArrow直接读Parquet比pandas快,因绕过DataFrame转换、可指定列/过滤/禁用类型推断、复用内存池、优化文件布局及合理并行;关键在读写协同调优。 PyArrow读取Parquet时为什么比pandas慢? 默认用pandas.read_parquet()且后端是pyarrow,其实底层调的仍是pyarrow.parquet.read_table(),但多了一层DataFra...

  • 如何优雅地捕获并处理 pandas.concat 的异常以继续执行程序
    05月272026

    本文介绍在使用pandas读取多个csv文件并合并时,如何正确捕获空文件等导致的异常,避免程序中断,同时保留日志反馈和流程可控性。 本文介绍在使用pandas读取多个csv文件并合并时,如何正确捕获空文件等导致的异常,避免程序中断,同时保留日志反馈和流程可控性。 在批量处理CSV元数据文件(如metadata_files列表)时,常见问题包括:文件为空、格式损坏、编码不兼容或列结构不一致。此时pd...

  • Python中SVM支持向量机如何选择核函数_对比Linear与RBF性能
    05月272026

    应优先用LinearSVC而非SVC(kernel='linear')处理高维稀疏数据,因其更快、更稳、可解释;RBF核仅在低维/中维且边界明显非线性时才值得调参,且必须标准化后手动设gamma。 线性核(kernel='linear')在高维稀疏数据或样本量远大于特征数时,往往比RBF更快、更稳、更可解释;RBF核(kernel='rbf')只在低维/中维且边界明显非线性时才值得投入调参成本——...

  • 如何在Python中进行PyTorch模型的性能剖析_使用torch.profiler工具
    05月272026

    torch.profiler.trace未生成ChromeTrace文件是因为默认不自动保存,需显式调用export_chrome_trace()且record_shapes=True;常见错误是仅使用withprofile但未导出,或prof初始化失败。 torch.profiler.trace为什么没生成预期的ChromeTrace文件 默认调用torch.profiler.profile不会...

  • 怎样提升Python中Timeit测试的准确性_利用-p参数进行性能剖析
    05月272026

    timeit不支持-p参数,官方文档和源码中均无此选项;正确性能剖析应使用cProfile、line_profiler或time.perf_counter()等专用工具。 timeit默认不启用Python解释器的优化开关,-p参数根本不存在——它不是timeit模块或命令行工具的合法选项。 为什么你搜不到-p参数? Python官方文档、源码(Lib/timeit.py)以及所有稳定版本(包括3...

  • Python中global与nonlocal关键字有什么区别_针对全局作用域与嵌套作用域的赋值
    05月272026

    必须用global:在函数内对已存在的模块级变量赋值且需影响全局时;必须用nonlocal:在嵌套函数中修改外层函数的局部变量且该变量非全局也非本层局部时。 global用于改模块级变量,nonlocal用于改外层函数的局部变量;写错一个,轻则值不更新,重则直接报UnboundLocalError或SyntaxError。 什么时候必须用global? 当你在函数内对一个**已经存在的模块级变量*...

  • 如何优化Python代码的CPU占用率_使用cProfile定位性能瓶颈函数
    05月262026

    cProfile通过tottime(自身耗时)精准定位真实CPU瓶颈,而非cumtime;运行python-mcProfile-stottime可按自身耗时排序,聚焦list.append、未编译正则、高占比自定义函数三类模式,避免误优化。 用cProfile快速定位高CPU占用函数 直接运行cProfile就能暴露真正吃CPU的函数,不用猜、不靠经验——它给出的是真实调用栈和累计时间。重点不是看...