面试手撕-shared_ptr
shared_ptr基本概念
std::shared_ptr 是C++标准库中的一个智能指针类型,它提供了自动的内存管理功能,通过引用计数机制来决定所管理的对象何时应该被删除。当最后一个指向对象的 shared_ptr 离开作用域或者被重置时,它所指向的对象会被自动删除,从而防止了内存泄漏。
实现一个shared_ptr
使用基础语法和标准库来实现一个shared_ptr所需要实现的成员变量和成员函数:
成员变量/属性
- 原始指针 (T* ptr): 用于存储实际的原始指针,指向动态分配的对象
- 引用计数 (std::size_t* ref_count): 用于跟踪有多少个 shared_ptr 实例共享同一个对象。通常是一个动态分配的整型指针,因为每个 shared_ptr 实例都需要能够修改这个计数。
成员函数
- 构造函数 (shared_ptr(T* ptr = nullptr)): 初始化 shared_ptr,如果给定指针,则分配新的引用计数并指向该对象。
- 拷贝构造函数 (shared_ptr(const shared_ptr& other)): 复制另一个 shared_ptr,增加引用计数。
- 移动构造函数 (shared_ptr(shared_ptr&& other)): 移动另一个 shared_ptr,不增加引用计数,而是将源 shared_ptr 设置为 nullptr。
- 析构函数 (~shared_ptr()): 释放资源,如果引用计数减至0,则删除原始指针指向的对象及引用计数本身。
- 重载赋值运算符 (copy assignment 和 move assignment): 类似于拷贝构造函数和移动构造函数,也需要更新引用计数。
- 解引用运算符 (T& operator*(), T* operator->()): 允许像普通指针一样访问对象。
- 获取原始指针 (T* get()): 返回原始指针。
- 重置 (void reset(T* ptr = nullptr)): 释放当前管理的对象(如果引用计数允许),并可选地开始管理一个新的对象。
- 获取引用计数 (可选,非标准功能)(std::size_t use_count()): 返回当前的引用计数。
最少实现的部分
2个成员变量是一定要设置的,对于成员函数:
构造函数、拷贝构造函数、析构函数、赋值运算符、*运算符、->运算符
代码实现
精简版实现
template<typename T>
class share_ptr{
public:
//默认构造函数
explicit shared_ptr(T* ptr = nullptr):m_ptr(ptr), m_refCount(new size_t(1)){}
//拷贝构造函数
shared_ptr(const shared_ptr<T>& sp):m_ptr(sp.m_ptr), m_refCount(sp.m_refCount){
(*m_refCount)++;
}
//析构函数
~shared_ptr(){
decreaseRefCountAndDeleteIfNecessary();
}
//运算符重载
//赋值运算符重载
shared_ptr<T> operator=(const shared_ptr<T>& sp){
if(this!=sp){
decreaseRefCountAndDeleteIfNecessary();
m_ptr = sp.m_ptr;
m_refCount = sp.m_refCount;
(*m_refCount)++;
}
return this;
}
//解引用运算符重载
T& operator*() const{
return *m_ptr;
}
//箭头运算符重载
T* operator->() {
return m_ptr;
}
private:
T* m_ptr;
std::size_t* m_refCount;
void decreaseRefCountAndDeleteIfNecessary(){ //当实例对象的shared_ptr出作用域的时候进行检查是否需要释放资源
if(--(*m_refCount) == 0){
delete m_ptr;
delete m_refCount;
}
}
};
完整版本
template <typename T>
class shared_ptr {
private:
T* m_ptr{nullptr};
std::size_t* m_refCount{nullptr};
public:
// 构造函数
explicit shared_ptr(T* ptr = nullptr) : m_ptr(ptr), m_refCount(new std::size_t(1)) {}
// 拷贝构造函数
shared_ptr(const shared_ptr& other) : m_ptr(other.m_ptr), m_refCount(other.m_refCount) {
++(*m_refCount);
}
// 赋值运算符(拷贝赋值)
shared_ptr& operator=(const shared_ptr& other) {
if (this != &other) {
if (--(*m_refCount) == 0) {
delete m_ptr;
delete m_refCount;
}
m_ptr = other.m_ptr;
m_refCount = other.m_refCount;
++(*m_refCount);
}
return *this;
}
// 解引用运算符
T& operator*() const {
return *m_ptr;
}
// 箭头操作符
T* operator->() const {
return m_ptr;
}
// 获取原始指针
T* get() const {
return m_ptr;
}
// 重置
void reset(T* ptr = nullptr) {
if (--(*m_refCount) == 0) {
delete m_ptr;
delete m_refCount;
}
m_ptr = ptr;
m_refCount = new std::size_t(1);
}
// 获取引用计数
std::size_t use_count() const {
return m_refCount ? *m_refCount : 0;
}
// 析构函数
~shared_ptr() {
if (--(*m_refCount) == 0) {
delete m_ptr;
delete m_refCount;
}
}
};