C++ 标准库中的 std::shared_ptr 和 std::unique_ptr 已经为我们提供了很好的智能指针实现,但在某些特定场景下,我们可能需要对内存回收策略进行更细粒度的控制,例如自定义对象的销毁时机、延迟销毁或使用自定义内存池。本文将演示如何实现一个简易的自定义智能指针 CustomPtr,支持两种内存回收策略:即时销毁和延迟销毁(基于引用计数)。
1. 需求分析
- 即时销毁:当指针不再被使用时立即调用析构函数。
- 延迟销毁:在引用计数降至 0 时才销毁对象,但可以在对象生命周期内将回收策略切换为即时销毁。
- 线程安全:延迟销毁的引用计数操作需要是线程安全的。
2. 基础结构
我们先定义一个基类 IReleaser,所有回收策略实现都将继承自该接口。
#include <atomic>
#include <iostream>
#include <memory>
#include <mutex>
class IReleaser {
public:
virtual void release(void* ptr) = 0;
virtual ~IReleaser() = default;
};
3. 即时销毁策略
即时销毁策略在 release 时直接调用 delete。
template<typename T>
class ImmediateReleaser : public IReleaser {
public:
void release(void* ptr) override {
delete static_cast<T*>(ptr);
}
};
4. 延迟销毁策略
延迟销毁需要一个线程安全的引用计数。我们使用 `std::atomic
`。 “`cpp template class DelayedReleaser : public IReleaser { public: DelayedReleaser() : ref_count_(0) {} // 增加引用计数 void addRef() { ref_count_.fetch_add(1, std::memory_order_relaxed); } // 减少引用计数并在计数为 0 时销毁 void release(void* ptr) override { if (ref_count_.fetch_sub(1, std::memory_order_acq_rel) == 1) { delete static_cast(ptr); } } private: std::atomic ref_count_; }; “` ### 5. 自定义智能指针实现 我们让 `CustomPtr` 与策略对象耦合。 “`cpp template class CustomPtr { public: // 构造函数 explicit CustomPtr(T* ptr = nullptr, IReleaser* releaser = nullptr) : ptr_(ptr), releaser_(releaser) { if (auto* dr = dynamic_cast*>(releaser_)) { dr->addRef(); // 初始化引用计数 } } // 拷贝构造 CustomPtr(const CustomPtr& other) : ptr_(other.ptr_), releaser_(other.releaser_) { if (auto* dr = dynamic_cast*>(releaser_)) { dr->addRef(); } } // 赋值 CustomPtr& operator=(const CustomPtr& other) { if (this != &other) { releaseCurrent(); ptr_ = other.ptr_; releaser_ = other.releaser_; if (auto* dr = dynamic_cast*>(releaser_)) { dr->addRef(); } } return *this; } // 析构 ~CustomPtr() { releaseCurrent(); } // 重载操作符 T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } T* get() const { return ptr_; } explicit operator bool() const { return ptr_ != nullptr; } private: void releaseCurrent() { if (ptr_ && releaser_) { releaser_->release(ptr_); } ptr_ = nullptr; } T* ptr_; IReleaser* releaser_; }; “` ### 6. 使用示例 “`cpp struct Widget { Widget() { std::cout imm; CustomPtr p1(new Widget, &imm); p1->say(); } // 作用域结束,立即销毁 // 延迟销毁 DelayedReleaser del; CustomPtr p2(new Widget, &del); { CustomPtr p3 = p2; // 拷贝,引用计数+1 p3->say(); } // p3 离开作用域,引用计数-1 // p2 仍然存在,引用计数>0,未销毁 std::cout 0,Widget 被销毁 } “` ### 7. 小结 通过策略模式和引用计数,我们实现了一个支持即时销毁和延迟销毁的自定义智能指针 `CustomPtr`。 – **即时销毁** 简单直接,适合资源不需要共享的场景。 – **延迟销毁** 通过线程安全的引用计数实现,适用于需要共享对象并在最后一次使用时销毁的场景。 如果需要进一步扩展,例如加入自定义内存池、懒加载或多线程同步等功能,只需在 `IReleaser` 基础上实现新的策略类即可。