【问题标题】: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 的间接关系,而我想在不再需要时使用某种类型的引用计数来关闭句柄。如果您可以分别使用createHandledestroyHandle 创建和销毁句柄,我认为它可能如下所示:

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 类函数
  • 其他可能性:句柄是某个数据结构中的索引或键,当计数为零时,您从数据结构中删除该对象。不过,您必须自己编写。
  • 这是我以前见过的骗子

标签: c++ c++11 shared-ptr handle


【解决方案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&lt;uintptr_t&gt;(ptr) 是将指针转换为整数的正确方法。
  • @NeilKirk,所以,像这样?
  • 假设 uintptr_t 足够大以容纳所有 int 值,是的。您可以使用std::numeric_limits 进行检查。
猜你喜欢
  • 1970-01-01
  • 2012-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-25
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
相关资源
最近更新 更多