Pool of curl handles
Please stop using new and delete.  

This is like reading old C code. Modern C++ rarely uses new and practically never uses delete (unless you are building stuff at a very low level). You should be using containers or smart pointers (always question the use of new and if you see a delete you are not using the facilities of the language).

curl_pool(const std::string &amp;root_cert, int size) : m_size(size) {
    m_handles = new CURL*[m_size];
}

virtual ~curl_pool() {
    delete m_handles;
      // Also note this should have been `delete [] m_handles;`
}


This breaks separation of concerns. You are doing memory management and business logic in the same object.

Also because you don't follow the rule of three. Your code is broken and will likely cause crashes.

The best way to fix this is to change m_handles into a vector.

std::vector&lt;CURL*&gt;     m_handles;


Let the vector handle the memory management. You can handle the business logic. PS. You still need to implement the rule of three.

Your connection is dangerious:

    void release() {
        m_pool.m_queue.push(m_index);
    }


What happens if I call release multiple times? I should not be able to break the code from the outside of the interface. Once you have released the handle you should make sure that a subsequent release does nothing and getting a CURL* should return nullptr.

Note I: Calling release() once will break the code. As the object will subsequently be destroyed and call release again.

Note II: Because your object is copyable. Passing it as a parameter will also break the code. As a copy is made and both the original and the new version will eventually be destroyed.

Looks like this should be a movable but not copyable object.