侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

实现一个线程安全的引用计数智能指针

2025-12-12 / 0 评论 / 4 阅读

题目

实现一个线程安全的引用计数智能指针

信息

  • 类型:问答
  • 难度:⭐⭐

考点

RAII原则,拷贝控制,移动语义,线程安全,运算符重载

快速回答

实现线程安全的引用计数智能指针需要:

  • 使用std::atomic保证引用计数的原子操作
  • 遵循RAII原则管理资源生命周期
  • 正确实现拷贝构造/赋值和移动构造/赋值
  • 重载operator*operator->提供指针语义
  • 处理自赋值和异常安全问题
## 解析

核心原理

引用计数智能指针通过计数器跟踪资源引用数,当计数归零时自动释放资源。线程安全需保证:

  • 引用计数的增减操作是原子的
  • 资源释放只发生一次
  • 避免拷贝时的竞态条件

代码实现

template<typename T>
class SafePtr {
    T* ptr;
    std::atomic<size_t>* count;

    void release() {
        if (count && --(*count) == 0) {
            delete ptr;
            delete count;
        }
    }

public:
    explicit SafePtr(T* p = nullptr) 
        : ptr(p), count(p ? new std::atomic<size_t>(1) : nullptr) {}

    // 拷贝构造
    SafePtr(const SafePtr& other) 
        : ptr(other.ptr), count(other.count) {
        if (count) (*count)++;
    }

    // 移动构造
    SafePtr(SafePtr&& other) noexcept 
        : ptr(other.ptr), count(other.count) {
        other.ptr = nullptr;
        other.count = nullptr;
    }

    // 拷贝赋值
    SafePtr& operator=(const SafePtr& other) {
        if (this != &other) {
            release();  // 释放原资源
            ptr = other.ptr;
            count = other.count;
            if (count) (*count)++;
        }
        return *this;
    }

    // 移动赋值
    SafePtr& operator=(SafePtr&& other) noexcept {
        if (this != &other) {
            release();
            ptr = other.ptr;
            count = other.count;
            other.ptr = nullptr;
            other.count = nullptr;
        }
        return *this;
    }

    ~SafePtr() { release(); }

    // 指针运算符重载
    T& operator*() const { return *ptr; }
    T* operator->() const { return ptr; }

    size_t use_count() const { 
        return count ? count->load() : 0; 
    }
};

最佳实践

  • 使用std::atomic确保计数器操作的原子性
  • 移动操作使用noexcept保证异常安全
  • 赋值运算符处理自赋值情况
  • 空指针安全处理(countnullptr时跳过操作)

常见错误

  • 未实现移动语义导致不必要的拷贝开销
  • 计数器非原子操作导致线程竞争
  • 自赋值未检查引发资源提前释放
  • 未处理空指针导致段错误
  • 异常安全不足(如构造函数失败时资源泄漏)

扩展知识

  • 循环引用问题:当两个对象相互持有时会导致内存泄漏,可通过weak_ptr解决
  • 删除器定制:标准库shared_ptr支持自定义删除器处理特殊资源
  • 线程安全级别:标准智能指针保证控制块线程安全,但被管理对象需额外同步
  • 性能影响:原子操作比非原子操作慢2-10倍,需根据场景选择
  • C++17改进shared_ptr支持数组类型,避免额外定义删除器