shared_ptr别名构造函数签名是shared_ptr(const shared_ptr& r, t* ptr),不接管ptr所有权而复用r的控制块;普通构造则新建控制块并独占资源管理。

shared_ptr别名构造函数怎么写,和普通构造差在哪
别名构造函数的签名是 shared_ptr<t>(const shared_ptr<u>& r, T* ptr)</u></t>,关键在第二个参数不是新分配的内存,而是指向 r 所管理对象内部某个子对象(比如成员、数组元素、转型后的地址)的裸指针。
它不接管 ptr 的所有权,只共享 r 的引用计数;ptr 的生命周期完全绑定到 r 上。这点和 shared_ptr<t>(new T)</t> 或 make_shared<t>()</t> 有本质区别——后者自己管内存,前者只是“借个视图”。
- 普通构造:新资源、新控制块、独立生命周期
- 别名构造:零额外分配、复用原控制块、生命周期严格从属
常见错误现象:shared_ptr<int>(sp, &sp.get()->val)</int> 看似合理,但如果 sp 是 shared_ptr<widget></widget>,而 val 是非 trivial 类型且被 move 走,这个 &val 就可能悬空——别名本身不阻止原对象内部状态变化。
典型场景:安全暴露内部成员或数组元素
最常用的就是让外部拿到某个字段的智能指针,但又不希望它影响整个对象的生存期决策。比如一个缓存容器持有 shared_ptr<vector>></vector>,用户只想持有一个 string& 的安全包装:
立即学习“C++免费学习笔记(深入)”;
auto data = make_shared<vector<string>>(1000); shared_ptr<string> first_str(data, &(*data)[0]); // 共享 data 的控制块
这时 first_str 可以放心传给其他模块,哪怕它被复制多次,只要 data 还活着,first_str.get() 就有效。
- 不要用
shared_ptr<string>(new string(...))</string>—— 额外分配、脱离原容器生命周期 - 不能用
shared_ptr<string>(&(*data)[0])</string>—— 控制块丢失,析构时 double-free 或 crash - 如果
vector后续 resize,&(*data)[0]地址可能失效,别名指针变成悬垂——这属于逻辑风险,别名构造本身不管这个
为什么不能用 static\_cast 或 get() 直接转?
static_cast<shared_ptr>>(sp)</shared_ptr> 编译不过(类型不匹配),shared_ptr<t>(sp.get())</t> 更危险:它会新建控制块,导致原始 sp 和新指针各自管理同一块内存,析构时必然 double-delete。
别名构造是唯一能「零开销复用控制块 + 改变所指类型」的机制。它的底层原理是把 ptr 存进已有的控制块,不碰 ref-count 内存布局,也不调用新的 deleter。
-
sp.get()返回的是原始U*,不能直接喂给shared_ptr<t></t>构造函数 -
dynamic_pointer_cast是类型安全向下转型,但它要求多态和虚函数,且仍需原shared_ptr是基类指针 - 别名构造不要求继承关系,
T和U可以完全无关(比如U=Buffer,T=char)
容易踩的坑:别名指针比原 shared_ptr 死得早?
不会。别名构造出来的 shared_ptr 和原 shared_ptr 共享同一个控制块,所以只要还有一个别名或原实例活着,资源就不会释放。但反过来说:如果原 shared_ptr 已经析构,所有别名都变成空(.get() == nullptr),访问会段错误。
真正危险的是「误以为别名能延长原对象寿命」。例如:
shared_ptr<BigObj> get_obj() { return make_shared<BigObj>(); }
auto p = shared_ptr<int>(get_obj(), &get_obj()->field); // 错!两个临时 shared_ptr,第一个立刻销毁
这里 get_obj() 调用两次,第一次返回的 shared_ptr 在表达式结束就析构了,p 持有的是已释放对象的字段地址。
- 必须确保传入的第一个参数是稳定存在的
shared_ptr变量(非临时量、非右值) - 数组场景下,
&arr[i]合法,但arr + i也合法;而arr.data() + i更推荐,语义清晰 - 如果目标是
const子对象,别名构造出shared_ptr<const t></const>完全没问题,类型转换自动发生
别名构造不是语法糖,它是 C++ 智能指针里少有的、允许你精确控制“谁决定内存生死”和“谁决定接口形态”分离的机制。用错一次,调试成本远高于写两行注释。










