(1)、具体讲一下shared_ptr自动管理内存的原理/引用计数的具体原理/shared_ptr引用计数什么时候会增加,什么时候会减少?
在shared_ptr的内部维护了⼀个计数器,来跟踪有多少个shared_ptr对象指向了某⼀个资源。当计数器的值减少到0的时候,shared_ptr就会调⽤delete(或者⽤户⾃定义的⽅法)来释放资源。
引用计数器何时增加:
1.新建⼀个shared_ptr并指向了⼀个资源时。
2.复制构造函数创建⼀个新的shared_ptr时。
3.⽤复制运算符将⼀个shared_ptr给另⼀个shared_ptr对象赋值时。
引⽤计数器何时减少:
1.当⼀个shared_ptr对象被销毁时,⽐如局部变量离开作⽤域,或者类成员变量析构时。
2.当⼀个shared_ptr对象不再指向⼀个资源时,例如通过reset⽅法或者赋值运算符指向另⼀个资源时。
(2)、shared_ptr是线程安全的吗
1、多线程代码操作的是同一个shared_ptr的对象是线程不安全的。
2、多线程代码操作的不是同一个shared_ptr的对象,但不同的shared_ptr指向了相同的内存,此时是线程安全的。
2、多线程情况下,管理同一个数据的shared_ptr在进行计数的增加和减少时是原子操作,是线程安全的。
(3)、手撕一下shared_ptr
(4)、
1. 基本原理说明(先讲理论再写代码)
"shared_ptr
是一种共享所有权的智能指针,通过引用计数机制管理对象的生命周期。多个 shared_ptr
可以指向同一个对象,当最后一个 shared_ptr
被销毁时,对象才会被删除。"
2. 关键组件
"它需要维护两个核心数据成员:
-
原始指针
T* ptr
-
引用计数
int* ref_count
(必须用指针,所有实例共享)
引用计数必须放在堆上,因为多个 shared_ptr
需要共享同一个计数器。"
3. 必须实现的成员函数
在写代码时,至少要包含以下核心实现:
template <typename T>
class SharedPtr {
private:
T* ptr;
int* ref_count;
void release() {
if (ref_count && --(*ref_count) == 0) {
delete ptr;
delete ref_count;
}
}
public:
// 1. 构造函数
explicit SharedPtr(T* p = nullptr)
: ptr(p), ref_count(p ? new int(1) : nullptr) {}
// 2. 拷贝构造函数
SharedPtr(const SharedPtr& other)
: ptr(other.ptr), ref_count(other.ref_count) {
if (ref_count) ++(*ref_count);
}
// 3. 移动构造函数
SharedPtr(SharedPtr&& other) noexcept
: ptr(other.ptr), ref_count(other.ref_count) {
other.ptr = nullptr;
other.ref_count = nullptr;
}
// 4. 析构函数
~SharedPtr() { release(); }
// 5. 拷贝赋值
SharedPtr& operator=(const SharedPtr& other) {
if (this != &other) {
release();
ptr = other.ptr;
ref_count = other.ref_count;
if (ref_count) ++(*ref_count);
}
return *this;
}
// 6. 移动赋值
SharedPtr& operator=(SharedPtr&& other) noexcept {
if (this != &other) {
release();
ptr = other.ptr;
ref_count = other.ref_count;
other.ptr = nullptr;
other.ref_count = nullptr;
}
return *this;
}
// 7. 解引用操作符
T& operator*() const { return *ptr; }
T* operator->() const { return ptr; }
// 8. 辅助函数
int use_count() const { return ref_count ? *ref_count : 0; }
void reset(T* p = nullptr) { /* 实现重置逻辑 */ }
};