C++成员初始化列表/类内初始化使用make_unique/make_shared的疑问
问题解答
写法合法性
你给出的构造函数写法完全合法,成员初始化列表中允许调用std::make_unique/std::make_shared,哪怕这两个函数可能抛出std::bad_alloc类异常也符合C规范。
如果初始化列表执行过程中抛出异常,C的异常安全机制会自动将已经构造完成的成员按初始化顺序的逆序析构,不会出现内存泄漏问题,无需额外处理。
ptr1与ptr2的初始化差异
对于示例中的场景,两种写法的执行效果完全一致,没有任何差异:
ptr1(std::make_unique<type>())采用直接初始化规则,调用std::unique_ptr<type>的移动构造函数完成初始化ptr2{std::make_unique<type>()}采用列表初始化规则,但由于std::unique_ptr没有接收std::initializer_list参数的构造函数,列表初始化会回退匹配普通构造函数,最终同样调用移动构造函数完成初始化
只有当目标类型是聚合类型,或者存在接收std::initializer_list参数的构造函数时,()和{}的初始化行为才会出现差异,对于std::unique_ptr、std::shared_ptr这类智能指针类型,两种写法在这里等价。
类内初始化使用make_unique/make_shared的合理性
这是非常推荐的最佳实践,优势主要有三点:
- 异常安全:相比直接写
ptr(new type)的写法,make_unique/make_shared把内存分配和智能指针构造合并为一个原子操作,不会出现表达式求值顺序导致的内存泄漏风险,初始化过程抛出异常也能保证资源完全释放 - 代码简洁:无需重复书写模板参数、手动调用
new,代码可读性更高,也降低了写错类型的概率 - 易维护:如果类存在多个构造函数,类内初始化可以统一指针的默认初始值,避免多个构造函数重复编写初始化逻辑,减少疏漏
唯一的不适用场景是你需要为指针对象指定自定义分配器、自定义删除器的时候,此时才需要手动构造智能指针。
内容的提问来源于stack exchange,提问作者Bruice
相关产品推荐
相关产品推荐

