《程序员面试金典》智能指针疑问:成员权限与标准库特性差异
问题解答
一、成员变量设为protected还是private?
原代码把ref、ref_count和remove()设为protected,核心目的是支持子类继承扩展。如果你的场景不需要基于这个SmartPointer做子类定制,改成private完全不影响正常运行——毕竟当前代码里没有子类,private成员只会被类自身访问,功能不受任何影响。
但如果后续需要扩展这个智能指针(比如加日志监控、自定义销毁逻辑的子类),protected能让子类直接访问这些核心成员和方法,private就会彻底限制子类的扩展能力。所以是否需要protected取决于你是否有继承需求,单纯使用的话private完全没问题。
二、对比std::shared_ptr,当前SmartPointer缺少的特性
当前实现确实是shared_ptr的简化版,但缺失了大量关键特性:
- 移动语义支持:没有移动构造函数和移动赋值运算符,无法通过
std::move转移所有权,每次传递都要增减引用计数,额外消耗性能。std::shared_ptr通过移动语义可以避免不必要的引用计数操作。 - 线程安全的引用计数:当前引用计数是普通unsigned变量,多线程环境下同时增减会导致竞态条件,引用计数错乱进而引发内存泄漏或重复释放。std::shared_ptr的引用计数是原子操作,保证多线程场景下的安全性。
- 自定义删除器:无法指定对象的销毁逻辑,比如针对数组的
delete[]、用free释放C风格内存,或者自定义资源清理动作(比如关闭文件句柄)。std::shared_ptr支持传入自定义删除器。 - 默认构造与空指针支持:没有默认构造函数,无法直接创建空的SmartPointer;也没有重载接受
nullptr的构造。std::shared_ptr可以默认构造为空,也能直接赋值nullptr。 - 原生指针式操作:没有重载
operator*和operator->,无法像原生指针那样直接用*ptr或ptr->member访问对象;也没有get()方法返回原始指针,仅有的getValue()返回的是对象副本(大对象场景会触发低效拷贝)。 - 弱指针支持:没有配套的弱指针(类似std::weak_ptr),无法解决循环引用导致的内存泄漏问题。
- 引用计数查询:没有
use_count()方法获取当前引用计数,无法调试或判断指针的使用情况。 - 数组类型支持:如果传入数组指针(比如
new Data[5]),析构时用delete会导致未定义行为,因为数组需要delete[]。std::shared_ptr<T[]>专门支持数组类型。 - 常量引用拷贝:当前拷贝构造和赋值的参数是
SmartPointer<T>&(非常量引用),无法拷贝临时对象(比如SmartPointer<Data>(new Data))。std::shared_ptr的拷贝构造是const std::shared_ptr<T>&,可以接受临时对象。
三、对比std::unique_ptr(删除拷贝构造后),当前SmartPointer缺少的特性
如果删除拷贝构造和赋值(SmartPointer(SmartPointer<T>& sptr) = delete;、operator=(SmartPointer<T>&) = delete;),确实能实现类似unique_ptr的“独占所有权”特性,但仍缺失这些核心功能:
- 移动语义支持:unique_ptr的核心是通过移动构造和赋值转移所有权,当前实现没有这些,删除拷贝后智能指针无法转移所有权,只能一直绑定到初始对象,灵活性极差。
- 自定义删除器:同样无法指定自定义删除器,比如针对数组的删除逻辑,或者资源清理函数。
- 所有权管理方法:没有
release()方法(释放所有权并返回原始指针)、reset()方法(重置指针,销毁当前对象并绑定新指针),无法手动管理所有权。 - 原生指针式操作:和shared_ptr一样,缺少
operator*、operator->和get(),使用体验远不如标准unique_ptr。 - 数组类型支持:同样不支持数组,传入数组指针会导致析构错误。
内容的提问来源于stack exchange,提问作者KcFnMi
相关产品推荐
相关产品推荐

