You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何std::make_shared<T>未设计为std::shared_ptr<T>的静态成员函数?

为什么std::make_shared不是std::shared_ptr<T>的静态成员函数?

这是一个关于理解设计决策的问题,而非对漏洞或缺陷的抱怨。在C++标准库中,用于创建shared_ptr及其对象的是一个独立函数:

template< class T, class... Args> std::shared_ptr<T> make_shared( Args&&... args );

为何该函数未被设计为std::shared_ptr<T>的static成员函数,如下所示:

template <class... Args> std::shared_ptr<T>::make(Args&&... args);

这样做可使std::命名空间更整洁,还能支持如下用法:

using shared_vector = std::shared_ptr<std::vector<int>>;

shared_vector a = shared_vector::make(7);

核心设计原因分析

1. 模板推导的灵活性与历史局限性

在C++17引入**类模板实参推导(CTAD)**之前,类的静态成员函数无法自动推导模板参数。如果make是shared_ptr<T>的静态成员,调用时必须先明确T的类型,比如shared_ptr<vector<int>>::make(7),这和直接写make_shared<vector<int>>(7)相比并没有简洁性优势。

而C++17之后,独立的make_shared可以借助CTAD实现更灵活的推导:

// C++17及以后,自动推导为shared_ptr<int>
auto ptr = std::make_shared(42);

这种灵活性是静态成员函数难以做到的——静态成员属于特定的shared_ptr<T>实例化,无法脱离T独立推导。

2. 标准库的设计一致性

C++标准库的设计习惯是将工厂类工具函数作为独立的命名空间成员,而非类的静态成员。比如std::make_pair、std::make_tuple、std::make_unique都遵循这个模式。这种设计将"对象创建"和"对象管理"的职责分离:shared_ptr专注于引用计数和资源释放,make_shared专注于高效的内存分配(一次性分配对象和控制块),职责划分更清晰。

3. 实现与扩展的便利性

make_shared的核心优势是内存分配优化:它会一次性分配存储对象和控制块的内存,减少内存碎片。这种实现逻辑放在独立函数中,不需要侵入shared_ptr的类定义,保持类接口的简洁。

另外,后续标准扩展的make_shared_for_overwrite等重载,作为独立函数可以轻松添加,不需要修改shared_ptr的类模板,避免了类接口的臃肿。

4. 对特殊场景的适配

对于需要自定义删除器的场景,独立的make_shared可以和其他工具函数更好地组合。同时,静态成员函数的形式会限制一些元编程场景的使用——比如在模板中传递工厂函数时,独立函数的语法更简洁。


内容的提问来源于stack exchange,提问作者Peter Fletcher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 16:05:16