【C++ 基础 】C++14 中为什么 make_shared / make_unique 更安全?
目录标题C14 中为什么 make_shared / make_unique 更安全一、最核心的原因避免裸 new二、异常安全更好三、代码更简洁也更不容易写错四、make_shared 通常效率更高直接写法make_shared 写法五、make_unique 同样推荐使用六、什么时候不一定用 make_shared1. 需要自定义删除器2. 不希望对象和控制块一起分配七、实战建议1. 能用 make_unique 就优先用 make_unique2. 需要共享所有权时再用 make_shared3. 尽量避免直接写裸 new八、总结参考示例推荐写法不太推荐的写法结语C14 中为什么make_shared/make_unique更安全在 C14 里创建智能指针时通常更推荐使用autop1std::make_sharedMyClass(args);autop2std::make_uniqueMyClass(args);而不是直接写std::shared_ptrMyClassp1(newMyClass(args));std::unique_ptrMyClassp2(newMyClass(args));很多初学者会问“它们不都是创建智能指针吗为什么make_版本更安全”这篇文章就来总结一下。一、最核心的原因避免裸new先看两种写法std::shared_ptrTp(newT(args));autopstd::make_sharedT(args);第二种写法最大的优势是不需要手动写new。为什么这很重要因为一旦代码里出现裸new就意味着对象先被创建出来然后再交给智能指针接管。如果这个过程中出现异常、重构失误或者写法稍复杂一点就有可能出现资源泄漏。而make_shared/make_unique把“创建对象”和“交给智能指针管理”合并成了一步风险更小。二、异常安全更好这是make_风格最经典的优点。看下面这段代码func(std::shared_ptrT(newT()),g());表面上看没问题但在 C14 中函数参数的求值顺序并没有规定。也就是说编译器可能这样执行先执行new T()再执行g()最后再构造shared_ptr如果第 2 步中的g()抛出异常那么刚才new T()创建出来的对象就可能来不及交给shared_ptr管理从而发生泄漏。而如果写成func(std::make_sharedT(),g());那么make_sharedT()内部会把对象创建和智能指针构造打包成一个完整过程。要么成功返回一个shared_ptr要么失败时自动清理不会把裸指针暴露在外面。这就是它“更安全”的关键所在。三、代码更简洁也更不容易写错直接构造智能指针时类型通常要写两遍std::shared_ptrMyTypep(newMyType(1,2));而make_shared只需要写一次autopstd::make_sharedMyType(1,2);这种好处看起来只是“简洁”但实际上它也提升了代码安全性少写一次类型减少重复修改类型时不容易漏改构造参数更直观阅读成本更低这属于工程层面的安全。也就是说它不一定是运行时安全问题但能明显减少人为失误。四、make_shared通常效率更高除了安全之外make_shared还有一个常见优势内存分配更高效。直接写法std::shared_ptrTp(newT(args));通常需要两次内存分配给对象T分配内存给shared_ptr的控制块分配内存引用计数、删除器等make_shared写法autopstd::make_sharedT(args);很多实现中make_shared可以把对象和控制块放在同一块内存里一次分配完成。这样做的好处是分配次数更少性能通常更好内存局部性更好少一次分配失败的机会当然这一点更多是“高效”不是最核心的“安全”。五、make_unique同样推荐使用在 C14 中std::make_unique已经正式可用所以创建unique_ptr时也建议优先写成autopstd::make_uniqueT(args);而不是std::unique_ptrTp(newT(args));原因和make_shared类似避免裸new异常安全更自然代码更简洁所有权表达更清晰尤其是unique_ptr本来就表示“独占所有权”配合make_unique会非常自然。六、什么时候不一定用make_shared虽然大多数情况下推荐make_shared但也不是绝对。1. 需要自定义删除器例如std::shared_ptrTp(newT,custom_deleter);这种场景下make_shared就不方便直接处理。2. 不希望对象和控制块一起分配make_shared通常会把对象和控制块放在同一块内存里。这在大多数时候是优点但某些特殊场景下反而可能不是最优。例如对象很大weak_ptr存活时间很长此时即使最后一个shared_ptr已经销毁只要控制块还因为weak_ptr存在而保留那么整块内存的释放策略就会受到影响。这属于偏进阶的话题日常开发里一般不用太纠结。七、实战建议在日常 C14 开发中可以记住一个简单原则1. 能用make_unique就优先用make_unique因为它表达独占所有权最直接。autopstd::make_uniqueMyClass();2. 需要共享所有权时再用make_sharedautopstd::make_sharedMyClass();3. 尽量避免直接写裸new除非你确实有特殊需求比如自定义删除器特殊内存管理策略必须分离对象和控制块八、总结C14 中make_shared/make_unique更安全核心原因可以概括为四点避免裸new异常安全更好对象创建后立即交给智能指针管理代码更简洁不容易写错其中最重要的一点其实是它把“创建资源”和“接管资源”合并成了一个更安全的整体。所以在大多数情况下可以记住一句很实用的话能用make_shared/make_unique就尽量不要手写new。参考示例推荐写法#includememoryclassTest{public:Test(intx){}};intmain(){autop1std::make_uniqueTest(10);autop2std::make_sharedTest(20);}不太推荐的写法#includememoryclassTest{public:Test(intx){}};intmain(){std::unique_ptrTestp1(newTest(10));std::shared_ptrTestp2(newTest(20));}结语在我们的编程学习之旅中理解是我们迈向更高层次的重要一步。然而掌握新技能、新理念始终需要时间和坚持。从心理学的角度看学习往往伴随着不断的试错和调整这就像是我们的大脑在逐渐优化其解决问题的“算法”。这就是为什么当我们遇到错误我们应该将其视为学习和进步的机会而不仅仅是困扰。通过理解和解决这些问题我们不仅可以修复当前的代码更可以提升我们的编程能力防止在未来的项目中犯相同的错误。我鼓励大家积极参与进来不断提升自己的编程技术。无论你是初学者还是有经验的开发者我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用不妨点击收藏或者留下你的评论分享你的见解和经验也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持也是对我持续分享和创作的动力。最后想特别推荐一下我出版的书籍——《C编程之禅从理论到实践》。这是对博主C 系列博客内容的系统整理与升华无论你是初学者还是有经验的开发者都能在书中找到适合自己的成长路径。从C语言基础到C20前沿特性从设计哲学到实际案例内容全面且兼具深度更加入了心理学和禅宗哲理帮助你用更好的心态面对编程挑战。本书目前已在京东、当当等平台发售推荐前往“清华大学出版社京东自营官方旗舰店”选购支持纸质与电子书双版本。希望这本书能陪伴你在C学习和成长的路上不断精进探索更多可能感谢大家一路以来的支持和关注期待与你在书中相见。阅读我的CSDN主页,解锁更多精彩内容:泡沫的CSDN主页