Search code examples
c++shared-ptr

Store libusb devices in easy-access container, without ownership


I'd like to store libusb_device_handle*s to be used by multiple clients (one handle can be used by multiple clients), so I thought about storing them with:

libusb_open(device, &handle);
libusb_claim_interface(handle, 0);
auto sharedHandle = std::shared_ptr<libusb_device_handle>(handle, [=](libusb_device_handle* handle) {
    libusb_release_interface(handle, 0);
    libusb_close(handle);
});

For reference, a client looks like:

struct Client
{
    Client(std::shared_ptr<libusb_device_handle> handle_, uint8_t endpoint_) : handle(handle_), endpoint(endpoint_) {}
    std::shared_ptr<libusb_device_handle> handle;
    uint8_t endpoint;
};

When all clients with same handle are destroyed the handle will also release the interface and close itself, which is great.

Thing is, when a new client is created it might ask an already opened std::shared_ptr<libusb_device_handle> (I'm using "Product String" as unique descriptor). I'm not sure how to store these. If I'll use a map to weak_ptr I won't be able to create a copy of already-created shared_ptrs. If I'll use a map of shared_ptr, the device won't ever get deleted because the map will always hold a reference.

What is the best approach here in terms of memory management & containers?


Solution

  • You can use a map with std::weak_ptr. weak_ptr provides a method lock() to create a shared_ptr from the weak_ptr as long as the shared object still exists.

    Your map could be something like this:

    #include <map>
    #include <memory>
    
    using libusb_device_handle = ...;
    using map_type = std::map<uint8_t, std::weak_ptr<libusb_device_handle>>;
    map_type map;
    
    Client get_client(uint8_t endpoint)
    {
        auto it = map.find(endpoint);
        if (it != map.end()) {
            return Client(it->second.lock(), endpoint);
        }
        return Client(std::shared_ptr<libusb_device_handle>(), endpoint);
    }
    

    Please note you will have to check if the shared_ptr evaluates to true if it contains a valid libusb_device_handle.