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_ptr
s. 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?
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.