Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>We need to store allocated resources somewhere (as it was already mentioned by <a href="https://stackoverflow.com/questions/2845183/how-to-handle-failure-to-release-a-resource-which-is-contained-in-a-smart-pointer/2885209#2885209">DeadMG</a>) and explicitly call some reporting/throwing function outside of any destructor. But that doesn't prevent us from taking advantage of reference counting implemented in boost::shared_ptr.</p> <pre><code>/** A TCP/IP connection. */ class Socket { private: //store internally every allocated resource here static std::vector&lt;boost::shared_ptr&lt;Socket&gt; &gt; pool; public: static boost::shared_ptr&lt;Socket&gt; connect(const std::string&amp; address) { //... boost::shared_ptr&lt;Socket&gt; socket(new Socket(address)); pool.push_back(socket); //the socket won't be actually //destroyed until we want it to return socket; } virtual ~Socket(); //call cleanupAndReport() as often as needed //probably, on a separate thread, or by timer static void cleanupAndReport() { //find resources without clients foreach(boost::shared_ptr&lt;Socket&gt;&amp; socket, pool) { if(socket.unique()) //there are no clients for this socket, i.e. //there are no shared_ptr's elsewhere pointing to this socket { //try to deallocate this resource if (close(socket-&gt;m_impl.fd) &lt; 0) { int error = errno; socket.reset(); //destroys Socket object //throw an exception or handle error in-place //... //throw Exception::fromErrno(error); } else { socket.reset(); } } } //foreach socket } protected: Socket(const std::string&amp; address); private: // not implemented Socket(const Socket&amp;); Socket&amp; operator=(const Socket&amp;); }; </code></pre> <p>The implementation of cleanupAndReport() should be a little more complicated: in the present version the pool is populated with null pointers after cleanup, and in case of throwing exception we have to call the function until it doesn't throw anymore etc, but I hope, it illustrates well the idea.</p> <p>Now, more general solution:</p> <pre><code>//forward declarations template&lt;class Resource&gt; boost::shared_ptr&lt;Resource&gt; make_shared_resource(); template&lt;class Resource&gt; void cleanupAndReport(boost::function1&lt;void,boost::shared_ptr&lt;Resource&gt; deallocator); //for every type of used resource there will be a template instance with a static pool template&lt;class Resource&gt; class pool_holder { private: friend boost::shared_ptr&lt;Resource&gt; make_shared_resource&lt;Resource&gt;(); friend void cleanupAndReport(boost::function1&lt;void,boost::shared_ptr&lt;Resource&gt;); static std::vector&lt;boost::shared_ptr&lt;Resource&gt; &gt; pool; }; template&lt;class Resource&gt; std::vector&lt;boost::shared_ptr&lt;Resource&gt; &gt; pool_holder&lt;Resource&gt;::pool; template&lt;class Resource&gt; boost::shared_ptr&lt;Resource&gt; make_shared_resource() { boost::shared_ptr&lt;Resource&gt; res(new Resource); pool_holder&lt;Resource&gt;::pool.push_back(res); return res; } template&lt;class Resource&gt; void cleanupAndReport(boost::function1&lt;void,boost::shared_ptr&lt;Resource&gt; &gt; deallocator) { foreach(boost::shared_ptr&lt;Resource&gt;&amp; res, pool_holder&lt;Resource&gt;::pool) { if(res.unique()) { deallocator(res); } } //foreach } //usage { boost::shared_ptr&lt;A&gt; a = make_shared_resource&lt;A&gt;(); boost::shared_ptr&lt;A&gt; a2 = make_shared_resource&lt;A&gt;(); boost::shared_ptr&lt;B&gt; b = make_shared_resource&lt;B&gt;(); //... } cleanupAndReport&lt;A&gt;(deallocate_A); cleanupAndReport&lt;B&gt;(deallocate_B); </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload