shared_ptr通过独立控制块实现引用计数,控制块包含指向对象的指针、强弱引用计数及删除器;多个shared_ptr共享同一控制块,构造、拷贝时增加强引用计数,析构或赋值时减少,归零则销毁对象;weak_ptr通过弱引用计数观察对象而不影响其生命周期;控制块支持自定义删除器与非侵入式管理,解耦计数与对象;多线程下引用计数操作为原子操作,保证线程安全;简化实现需注意原子性、控制块生命周期、自赋值检查与异常安全;相比unique_ptr的独占所有权,shared_ptr适用于共享所有权场景,但有性能开销。

C++中
shared_ptr
shared_ptr
weak_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
控制块(Control Block):
T* ptr
std::atomic_long shared_count
shared_ptr
std::atomic_long weak_count
weak_ptr
Deleter
Allocator
shared_ptr
shared_ptr
立即学习“C++免费学习笔记(深入)”;
shared_ptr
T*
ControlBlock*
引用计数的生命周期管理:
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
delete
weak_ptr
weak_ptr
weak_ptr
weak_ptr
weak_ptr
weak_ptr
lock()
shared_ptr
shared_ptr
这种设计确保了在多个
shared_ptr
shared_ptr
shared_ptr
在我看来,
shared_ptr
首先,它实现了引用计数与被管理对象的解耦。想象一下,如果引用计数直接内嵌在被管理对象内部,那么所有被
shared_ptr
new
shared_ptr
其次,支持自定义删除器和分配器。控制块是存储这些自定义逻辑的理想场所。比如,你可能需要用
free()
delete
shared_ptr
shared_ptr
再者,weak_ptr
weak_ptr
shared_ptr
weak_ptr
weak_ptr
weak_ptr
从内存布局和性能角度看,虽然引入控制块会增加一点点内存开销和间接性,但它避免了对被管理对象本身的侵入式修改,这在很多场景下是不可接受的。而且,对于同一个对象,无论有多少个
shared_ptr
shared_ptr
shared_ptr
多线程环境下,引用计数的安全性是
shared_ptr
int
shared_ptr
std::atomic
std::atomic_long
fetch_add
fetch_sub
具体来说:
原子性增减:当一个
shared_ptr
shared_count
weak_count
std::atomic_long::fetch_add(1)
内存顺序(Memory Ordering):除了原子操作本身,现代处理器为了性能优化,可能会重排指令的执行顺序。这可能导致在一个线程中对共享变量的修改,在另一个线程中无法立即看到,或者看到的是旧值。
std::atomic
memory_order_seq_cst
memory_order_acquire
release
性能考量:原子操作通常比非原子操作要慢,因为它们可能涉及CPU缓存同步、内存屏障(memory barrier)等开销。然而,这种开销是保证多线程环境下正确性的必要代价。
shared_ptr
shared_ptr
shared_ptr
在我看来,
shared_ptr
shared_ptr
自己动手实现一个简化的
shared_ptr
首先,我们需要一个独立的控制块(
ControlBlock
#include <atomic> // 用于线程安全的引用计数
#include <iostream>
#include <functional> // 用于自定义删除器
// 简化的ControlBlock
class ControlBlockBase {
public:
std::atomic_long shared_count; // 强引用计数
std::atomic_long weak_count; // 弱引用计数
ControlBlockBase() : shared_count(1), weak_count(0) {}
virtual ~ControlBlockBase() = default;
// 纯虚函数,用于销毁被管理对象
virtual void destroy_object() = 0;
};
template<typename T, typename Deleter = std::default_delete<T>>
class ControlBlock : public ControlBlockBase {
public:
T* ptr;
Deleter deleter;
ControlBlock(T* p, Deleter d = Deleter()) : ptr(p), deleter(d) {}
void destroy_object() override {
if (ptr) {
deleter(ptr); // 使用自定义删除器或默认删除器
ptr = nullptr; // 避免二次删除
}
}
};接下来是
MySharedPtr
template<typename T>
class MySharedPtr {
private:
T* data_ptr;
ControlBlockBase* control_block;
void release() {
if (control_block) {
// 原子递减强引用计数
if (control_block->shared_count.fetch_sub(1) == 1) {
// 如果强引用计数归零,销毁对象
control_block->destroy_object();
// 如果弱引用计数也归零,销毁控制块
if (control_block->weak_count.load() == 0) {
delete control_block;
control_block = nullptr;
}
}
}
}
public:
// 默认构造函数
MySharedPtr() : data_ptr(nullptr), control_block(nullptr) {}
// 裸指针构造函数
template<typename U>
explicit MySharedPtr(U* p) : data_ptr(p) {
if (p) {
control_block = new ControlBlock<U>(p);
} else {
control_block = nullptr;
}
}
// 带自定义删除器的裸指针构造函数
template<typename U, typename Deleter>
MySharedPtr(U* p, Deleter d) : data_ptr(p) {
if (p) {
control_block = new ControlBlock<U, Deleter>(p, d);
} else {
control_block = nullptr;
}
}
// 拷贝构造函数
MySharedPtr(const MySharedPtr& other) noexcept
: data_ptr(other.data_ptr), control_block(other.control_block) {
if (control_block) {
control_block->shared_count.fetch_add(1); // 原子递增强引用计数
}
}
// 移动构造函数
MySharedPtr(MySharedPtr&& other) noexcept
: data_ptr(other.data_ptr), control_block(other.control_block) {
other.data_ptr = nullptr;
other.control_block = nullptr;
}
// 拷贝赋值运算符
MySharedPtr& operator=(const MySharedPtr& other) noexcept {
if (this != &other) { // 处理自赋值
release(); // 释放当前资源
data_ptr = other.data_ptr;
control_block = other.control_block;
if (control_block) {
control_block->shared_count.fetch_add(1); // 原子递增强引用计数
}
}
return *this;
}
// 移动赋值运算符
MySharedPtr& operator=(MySharedPtr&& other) noexcept {
if (this != &other) { // 处理自赋值
release(); // 释放当前资源
data_ptr = other.data_ptr;
control_block = other.control_block;
other.data_ptr = nullptr;
other.control_block = nullptr;
}
return *this;
}
// 析构函数
~MySharedPtr() {
release();
}
// 解引用运算符
T& operator*() const noexcept {
return *data_ptr;
}
// 箭头运算符
T* operator->() const noexcept {
return data_ptr;
}
// 获取裸指针
T* get() const noexcept {
return data_ptr;
}
// 获取引用计数
long use_count() const noexcept {
return control_block ? control_block->shared_count.load() : 0;
}
// 检查是否拥有对象
explicit operator bool() const noexcept {
return data_ptr != nullptr;
}
};
// 辅助函数:make_shared (简化版,不处理完美转发和内存优化)
template<typename T, typename... Args>
MySharedPtr<T> make_my_shared(Args&&... args) {
// 实际的make_shared会一次性分配对象和控制块的内存,这里简化处理
return MySharedPtr<T>(new T(std::forward<Args>(args)...));
}需要注意的关键点:
shared_count
weak_count
std::atomic
ControlBlockBase
T
Deleter
destroy_object()
if (this != &other)
shared_ptr
std::make_shared
Deleter
std::function
shared_ptr
weak_ptr
MyWeakPtr
MyWeakPtr
ControlBlockBase*
weak_count
weak_count
MyWeakPtr::lock()
shared_count
shared_count
MySharedPtr
ControlBlockBase
ControlBlock
MySharedPtr
MySharedPtr
T
通过这个练习,你会发现标准库的
std::shared_ptr
shared_ptr
unique_ptr
weak_ptr
在C++智能指针家族中,
shared_ptr
unique_ptr
weak_ptr
1. unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
unique_ptr
shared_ptr
unique_ptr
以上就是C++如何实现shared_ptr引用计数机制的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号