vendredi 1 décembre 2017

C++11: Returning std::unique_ptr with Custom Lambda Deleter

Question:

Does anyone know of a way to return a std::unique_ptr which uses a custom deleter defined as a lambda? Failing that, does anyone know of a better overall approach to the below problem?

Background:

I am working on a C++11 database connection pool. The idea is fairly simple, however I seem to be stuck on the actual connection pointer returning.

The overall design of my connection pool is to pre-create a number of connections which are stored in a std::vector along with a bool to indicate if the given connection is available:

static std::vector<std::pair<DataStore*, bool>> connList;

The plan is to, on request, return std::unique_ptr objects with a custom deleter. This deleter will not actually free the connection but, instead, will reset the bool to allow the connection to be handed out to subsequent requesters. In this way, consumers of the class don't have to remember to release the connection object.

The problem I am having is that I am not sure how to actually return this std::unique_ptr with the associated deleter, which is specified in a template parameter. AFAIK, a lambda is the only way to capture the vector index needed to reset the bool. My current implementation of this lambda is simple:

auto connDeleter = [index](DataStore* p) { connList[index].second = true; };

And my attempted solution:

return std::unique_ptr<DataStore, decltype(connDeleter)>
    (connList[index].first, connDeleter);

Unfortunately, this requires all external consumers of the class to know about connDeleter, which doesn't make any sense as index and connList have no meaning outside of the function in question.

AFAIK, any of the other solutions (functors or free functions) will not allow me to receive any kind of index to reset the connection. I could wrap the pointer and index in an intermediate object and override the dereference operator to "pass through" to the underlying pointer. This would allow me to update / extract whatever from the intermediate object however this feels really hacky to me. Also not sure about the performance impact of an extra object.

Further Information:

  • This pool will be concurrently accessed via many threads. Database operations are not homogeneous so connections can be returned in any order.

  • I would prefer to hide as much of this deleter business from the consumer.

  • For my application, speed is more important that space.

Aucun commentaire:

Enregistrer un commentaire