Reference count for a handle instead of a pointer

C++11 introduces smart pointers like std::shared_ptr. The class stores a pointer and a reference counter. When the reference counter hits zero, a callback (deleter) is called. My question is whether C++11 has an easy way to use the reference counter of std::shared_ptr without the pointer.

I use a c-style library which gives me an integer as handle. I want to create a class to wrap the handle. I would like to avoid the indirection with std::shared_ptr while I want to have some type of reference counting to close the handle when it is not needed anymore. If you can create and destroy the handle with createHandle and destroyHandle respectively, I think it could look like this:

class WrapperClass
{
public:
    WrapperClass() :
        mHandle(createHandle(), &destroyHandle)
    {
    }
private:
    shared_data<int> mHandle;
}

or

class WrapperClass
{
public:
    WrapperClass() :
        mHandle(createHandle()),
        mRefCount([this](){destroyHandle(mHandle);})
    {
    }
private:
    int mHandle;
    reference_counter mRefCount;
}

Another problem with this is that I’m not sure if it is possible to have working specifiers like const. I mean things like that it is not possible to remove the const-specifier without using casts. I don’t see any way to do it.

Answer

With some precautions you can try using original shared_ptr for this task:

#include <iostream>
#include <memory>

int create_handle() {
    std::cout << "allocn";
    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();
}

I believe you must be sure your handle can be represented as pointer (matching size and align). Then you can apply reinterpret_cast black magic. As you basically just convert int to pointer and back using reinterpret cast, but never dereference pointer, it should be safe

Leave a Reply

Your email address will not be published. Required fields are marked *