C++11中使用make_shared初始化shared_ptr是否会创建临时副本及相关线程安全疑问
咱们一步一步来拆解你提出的两个核心问题:
1. make_shared返回的shared_ptr会不会触发拷贝构造函数?
首先要明确你写的代码形式:std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(/*构造参数*/); 这属于复制初始化,但别担心,这里不会触发拷贝构造——原因有两个:
- 首先,
std::make_shared返回的是一个右值(临时的shared_ptr对象),在C++11及以后,std::shared_ptr提供了移动构造函数,编译器会优先选择移动构造而非拷贝构造。移动构造只会转移shared_ptr的所有权,不会复制引用计数等内部资源,开销极低。 - 其次,哪怕不考虑移动构造,C++11里的复制消除(虽然不是强制要求)几乎所有主流编译器(GCC、Clang、MSVC)都会对这种“直接用函数返回值初始化变量”的场景做优化,直接在目标变量
ptr的内存空间上构造make_shared生成的shared_ptr,完全不会产生临时对象,自然也不会调用拷贝/移动构造。
简单说:不管是移动构造还是复制消除优化,你都不用担心拷贝构造被触发的问题。
2. 初始化过程中需要加锁保证线程安全吗?
答案是不需要,理由如下:
std::shared_ptr的引用计数操作本身是原子的,也就是说,当多个shared_ptr实例指向同一个对象时,它们对引用计数的增减操作是线程安全的,不会出现竞态条件。- 你的场景是初始化一个新的
shared_ptr变量,在这个变量完全初始化完成、没有被发布到其他线程之前,其他线程根本无法访问到它。就算有其他线程调用use_count(),那也是针对它们自己的shared_ptr实例,和你正在初始化的这个ptr没关系。 - 要注意的是:
shared_ptr的线程安全仅针对不同实例指向同一对象时的引用计数操作,如果多个线程同时读写同一个shared_ptr实例(比如一个线程给它赋值,另一个线程读它),那还是需要加锁的,但你的初始化场景完全不涉及这种情况。
总结一下:你写的初始化方式既不会触发不必要的拷贝构造,也不需要额外加锁来保证线程安全。
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

