cpp
#pragma once
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <chrono>
#include <memory>
#include <thread>
#include <cstdint>
#include <utility>
template<typename T>
class RefCountNotifier {
public:
// 构造函数:仅初始化通知器,不持有任何业务层指针的强引用
RefCountNotifier() : m_isReleased(false) {}
// 创建业务层的shared_ptr(核心:创建后不保留副本,仅返回给上层)
std::shared_ptr<T> CreateSharedPtr(T* rawPtr, std::function<void(T*)> deleter) {
if (IsReleased()) {
return nullptr; // 已释放,拒绝创建
}
// 自定义删除器:释放指针时通知等待的线程
auto customDeleter = [this, origDeleter = std::move(deleter)](T* p) {
// 1. 执行原始析构逻辑
if (origDeleter) {
origDeleter(p);
}
// 2. 标记释放并通知
std::lock_guard<std::mutex> innerLock(m_mutex);
m_isReleased = true;
m_cv.notify_all();
std::cout << "[INFO] 业务层指针引用计数归0,触发释放通知" << std::endl;
};
// 3. 创建shared_ptr并返回给上层(不存储为成员,不持有强引用)
std::shared_ptr<T> ptr(rawPtr, std::move(customDeleter));
return ptr;
}
// 等待业务层指针释放(超过5秒打印日志,继续等待)
void WaitForRelease() {
std::unique_lock<std::mutex> lock(m_mutex);
const auto timeout = std::chrono::seconds(5);
// 循环等待,直到m_isReleased为true(指针已释放)
while (!m_isReleased) {
// 等待5秒,超时则打印日志并继续等待
if (!m_cv.wait_for(lock, timeout, [this]() { return m_isReleased; })) {
std::cerr << "[WARNING] 释放句柄等待超过5秒,继续等待..." << std::endl;
}
}
}
// 判断是否已释放
bool IsReleased() const {
std::lock_guard<std::mutex> lock(m_mutex);
return m_isReleased;
}
private:
mutable std::mutex m_mutex; // mutable允许const方法加锁
std::condition_variable m_cv; // 释放通知的条件变量
bool m_isReleased; // 标记业务层指针是否已释放
};
template<typename T>
class ConvertHandle {
public:
// 核心修改:传入二级指针 T**,用于修改上层的裸指针变量
static int32_t CreateHandle(T** pptr, std::function<void(T*)> deleter = [](T* p) { delete p; }) {
// 合法性校验:二级指针本身不能为空 + 二级指针指向的裸指针不能为空
if (!pptr || !*pptr) {
std::cerr << "[ERROR] 无效指针:二级指针为空或裸指针为空" << std::endl;
return -1;
}
// 1. 保存临时裸指针,用于后续处理(避免置空后丢失原指针地址)
T* tempPtr = *pptr;
// 2. 关键步骤:解引用二级指针,将上层的裸指针置为nullptr,使其失效
*pptr = nullptr;
std::cout << "[INFO] 上层裸指针已被置空,无法再操作原内存" << std::endl;
// 3. 调用内部方法处理临时裸指针(逻辑与原有一致)
return getInstance().CreateHandleInternal(tempPtr, std::move(deleter));
}
static int32_t DestroyHandle(int32_t oHandle) {
if (oHandle <= 0) return -1;
return getInstance().DestroyHandleInternal(oHandle);
}
static std::shared_ptr<T> GetPtr(int32_t oHandle) {
if (oHandle <= 0) return nullptr;
return getInstance().GetPtrInternal(oHandle);
}
private:
// 辅助结构体:替代C++17的结构化绑定,存储通知器和业务层指针
struct HandleEntry {
std::shared_ptr<RefCountNotifier<T>> notifier;
std::shared_ptr<T> businessPtr;
// C++11默认构造、移动构造(保证std::move语义正常)
HandleEntry() = default;
HandleEntry(std::shared_ptr<RefCountNotifier<T>> n, std::shared_ptr<T> b)
: notifier(std::move(n)), businessPtr(std::move(b)) {}
HandleEntry(HandleEntry&& other) noexcept
: notifier(std::move(other.notifier)), businessPtr(std::move(other.businessPtr)) {}
HandleEntry& operator=(HandleEntry&& other) noexcept {
if (this != &other) {
notifier = std::move(other.notifier);
businessPtr = std::move(other.businessPtr);
}
return *this;
}
// 禁止拷贝(保持原有语义)
HandleEntry(const HandleEntry&) = delete;
HandleEntry& operator=(const HandleEntry&) = delete;
};
int32_t CreateHandleInternal(T* rawPtr, std::function<void(T*)> deleter) {
// 1. 创建空的通知器(不持有任何指针)
auto notifier = std::make_shared<RefCountNotifier<T>>();
// 2. 让通知器创建业务层shared_ptr(仅返回给map存储,通知器不保留)
auto businessPtr = notifier->CreateSharedPtr(rawPtr, std::move(deleter));
if (!businessPtr) {
if (deleter) {
deleter(rawPtr);
} else {
delete rawPtr;
}
return -1;
}
// 3. 生成句柄并存储(map存储:句柄 → (通知器,业务层指针))
std::lock_guard<std::mutex> lock(m_mutexHandle);
int32_t newHandle = 0;
do {
m_index = (m_index >= INT32_MAX - 1) ? 1 : m_index + 1;
newHandle = m_index;
} while (m_mapHandle.find(newHandle) != m_mapHandle.end());
// 存储通知器和业务层指针(使用自定义HandleEntry,替代C++17的pair结构化绑定)
m_mapHandle[newHandle] = HandleEntry(std::move(notifier), std::move(businessPtr));
return newHandle;
}
int32_t DestroyHandleInternal(int32_t oHandle) {
// 1. 从map中取出并删除(释放map对通知器和业务层指针的引用)
HandleEntry entry;
{
std::lock_guard<std::mutex> lock(m_mutexHandle);
auto it = m_mapHandle.find(oHandle);
if (it == m_mapHandle.end()) {
return -1; // 句柄无效
}
// 移动取出entry,避免拷贝
entry = std::move(it->second);
m_mapHandle.erase(it);
std::cout << "[INFO] 句柄" << oHandle << "已从map中移除" << std::endl;
// 2. 先释放map持有的业务层指针引用(关键!)
entry.businessPtr.reset();
std::cout << "[INFO] 释放map持有的业务层指针引用" << std::endl;
}
// 3. 等待业务层指针完全释放(此时仅上层持有的指针会影响计数)
if (!entry.notifier->IsReleased()) {
std::cout << "[INFO] 开始等待业务层指针释放..." << std::endl;
entry.notifier->WaitForRelease();
}
std::cout << "[INFO] 句柄" << oHandle << "释放完成" << std::endl;
return 0;
}
std::shared_ptr<T> GetPtrInternal(int32_t oHandle) {
std::shared_ptr<T> businessPtr;
std::lock_guard<std::mutex> lock(m_mutexHandle);
auto it = m_mapHandle.find(oHandle);
if (it == m_mapHandle.end()) {
return nullptr;
}
// C++11不支持结构化绑定,直接访问HandleEntry的成员变量
const HandleEntry& entry = it->second;
businessPtr = entry.businessPtr;
/*
// 检查是否已释放
if (notifier->IsReleased()) {
return nullptr;
}
*/
// 返回业务层指针的拷贝(引用计数+1)
return businessPtr;
}
static ConvertHandle<T>& getInstance() {
static ConvertHandle<T> instance;
return instance;
}
private:
// map存储:句柄 → 自定义HandleEntry(替代原C++17的pair)
std::unordered_map<int32_t, HandleEntry> m_mapHandle;
std::mutex m_mutexHandle;
int32_t m_index = 0;
// 禁止拷贝
ConvertHandle() = default;
ConvertHandle(const ConvertHandle&) = delete;
ConvertHandle& operator=(const ConvertHandle&) = delete;
};
#include <iostream>
// 测试代码:验证逻辑正确性
int main() {
// 测试用的业务类
class TestObj {
public:
~TestObj() {
std::cout << "[INFO] TestObj 析构函数执行(真正释放资源)" << std::endl;
}
};
// 1. 创建句柄
TestObj* obj = new TestObj();
int32_t handle = ConvertHandle<TestObj>::CreateHandle(&obj);
std::cout << "[INFO] 创建句柄:" << handle << std::endl;
// 2. 上层获取指针(引用计数+1)
auto upperPtr1 = ConvertHandle<TestObj>::GetPtr(handle);
std::cout << "[INFO] 上层第一次获取指针,引用计数:" << upperPtr1.use_count() << std::endl;
// 3. 模拟另一个线程持有指针6秒后释放
std::thread t([&]() {
auto upperPtr2 = ConvertHandle<TestObj>::GetPtr(handle);
std::cout << "[INFO] 子线程获取指针,引用计数:" << upperPtr2.use_count() << std::endl;
std::cout << "[INFO] 子线程持有指针6秒..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(6));
upperPtr2.reset();
std::cout << "[INFO] 子线程释放指针" << std::endl;
});
// 5. 释放上层最后一个指针
upperPtr1.reset();
// 4. 主线程立即销毁句柄(会等待,超过5秒打印日志)
std::cout << "[INFO] 主线程开始销毁句柄..." << std::endl;
int ret = ConvertHandle<TestObj>::DestroyHandle(handle);
std::cout << "[INFO] 句柄销毁结果:" << ret << std::endl;
std::cout << "[INFO] 主线程释放最后一个指针" << std::endl;
// 等待子线程结束
t.join();
return 0;
}
功能和效果
1: 可以把指针转化成句柄,通过句柄来管理释放,保证创建,使用,释放实现多线程安全。
2:代码性能基本高效,unordered_map 的时间复杂度平均O(1)
3:可以很方便改造已有的代码