句柄而不是指针的引用计数
Posted
技术标签:
【中文标题】句柄而不是指针的引用计数【英文标题】:Reference count for a handle instead of a pointer 【发布时间】:2015-10-12 19:50:31 【问题描述】:C++11 引入了像std::shared_ptr
这样的智能指针。该类存储一个指针和一个引用计数器。当引用计数器达到零时,将调用回调(删除器)。我的问题是 C++11 是否有一种简单的方法可以在没有指针的情况下使用 std::shared_ptr
的引用计数器。
我使用了一个 c 风格的库,它给了我一个整数作为句柄。我想创建一个类来包装句柄。我想避免与std::shared_ptr
的间接关系,而我想在不再需要时使用某种类型的引用计数来关闭句柄。如果您可以分别使用createHandle
和destroyHandle
创建和销毁句柄,我认为它可能如下所示:
class WrapperClass
public:
WrapperClass() :
mHandle(createHandle(), &destroyHandle)
private:
shared_data<int> mHandle;
或
class WrapperClass
public:
WrapperClass() :
mHandle(createHandle()),
mRefCount([this]()destroyHandle(mHandle);)
private:
int mHandle;
reference_counter mRefCount;
另一个问题是我不确定是否可以使用像const
这样的工作说明符。我的意思是,如果不使用强制转换,就不可能删除 const
-specifier。我看不出有什么办法。
【问题讨论】:
我想知道你是否可以强力支持 shared_ptr 这样做。您可能会为(可能是 int)句柄编写一个简单的包装类,只是为了拥有一个自定义类型,然后为该类定义您自己的自定义运算符 free() ,它要么什么都不做,要么可能处置句柄,但什么都没有与免费商店有关。为此编写自己的 shared_resource 类可能更明智;但魔鬼可能在细节上完全正确。 如果您向自己保证永远不会将整数值存储在int
中,那么您可以使用隐式转换运算符制作一个简单的包装器到int
。承诺可以防止您在没有引用计数的情况下取出值,同时仍然允许您在库需要int
描述符的任何地方将其用作函数参数。包装类将类似于 RAII 类。
@MicroVirus 而不是 promises 更好地为所有 C API 函数编写 warpper 类函数
其他可能性:句柄是某个数据结构中的索引或键,当计数为零时,您从数据结构中删除该对象。不过,您必须自己编写。
这是我以前见过的骗子
【参考方案1】:
采取一些预防措施,您可以尝试使用原始 shared_ptr 来完成此任务:
#include <iostream>
#include <memory>
int create_handle()
std::cout << "alloc\n";
return 42;
void delete_handle(int handle)
std::cout << "delete " << handle << "\n";
class Wrapper
public:
Wrapper():
_d(Wrapper::create_handle(), &Wrapper::delete_handle)
int value()
return reinterpret_cast<uintptr_t>(_d.get());
private:
std::shared_ptr<void> _d;
static void* create_handle()
static_assert(sizeof(create_handle()) <= sizeof(void*), "can't fit");
static_assert(alignof(create_handle()) <= sizeof(void*), "can't align");
return reinterpret_cast<void*>(static_cast<uintptr_t>(::create_handle()));
static void delete_handle(void* handle)
return ::delete_handle(reinterpret_cast<unintptr_t>(handle));
;
int main()
Wrapper w;
std :: cout << w.value();
我相信您必须确保您的句柄可以表示为指针(匹配大小和对齐)。然后你可以申请reinterpret_cast
黑魔法。因为您基本上只是将int
转换为指针并使用重新解释转换返回,但从不取消引用指针,它应该是安全的
【讨论】:
按值而不是按引用进行转换,即使这样也不能保证有效,尽管它可能在许多系统上都有效。 @NeilKirk,你的意思是 void* -> int 转换吗?它甚至不适用于我的 Ubuntu。你的理由是什么?reinterpret_cast<uintptr_t>(ptr)
是将指针转换为整数的正确方法。
@NeilKirk,所以,像这样?
假设 uintptr_t
足够大以容纳所有 int 值,是的。您可以使用std::numeric_limits
进行检查。以上是关于句柄而不是指针的引用计数的主要内容,如果未能解决你的问题,请参考以下文章