Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 801789
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 14, 20262026-05-14T23:29:49+00:00 2026-05-14T23:29:49+00:00

How should an error during resource deallocation be handled, when the object representing the

  • 0

How should an error during resource deallocation be handled, when the
object representing the resource is contained in a shared pointer?

EDIT 1:

To put this question in more concrete terms: Many C-style interfaces
have a function to allocate a resource, and one to release
it. Examples are open(2) and close(2) for file descriptors on POSIX
systems, XOpenDisplay and XCloseDisplay for a connection to an X
server, or sqlite3_open and sqlite3_close for a connection to an
SQLite database.

I like to encapsulate such interfaces in a C++ class, using the Pimpl
idiom to hide the implementation details, and providing a factory
method returning a shared pointer to ensure that the resource is
deallocated when no references to it remain.

But, in all the examples given above and many others, the function
used to release the resource may report an error. If this function is
called by the destructor, I cannot throw an exception because
generally destructors must not throw.

If, on the other hand, I provide a public method to release the
resource, I now have a class with two possible states: One in which
the resource is valid, and one in which the resource has already been
released. Not only does this complicate the implementation of the
class, it also opens a potential for wrong usage. This is bad, because
an interface should aim to make usage errors impossible.

I would be grateful for any help with this problem.

The original statement of the question, and thoughts about a possible
solution follow below.

EDIT 2:

There is now a bounty on this question. A solution must meet these
requirements:

  1. The resource is released if and only if no references to it remain.
  2. References to the resource may be destroyed explicitly. An exception is thrown if an error occured while releasing the resource.
  3. It is not possible to use a resource which has already been released.
  4. Reference counting and releasing of the resource are thread-safe.

A solution should meet these requirements:

  1. It uses the shared pointer provided by boost, the C++ Technical Report 1 (TR1), and the upcoming C++ standard, C++0x.
  2. It is generic. Resource classes only need to implement how the resource is released.

Thank you for your time and thoughts.

EDIT 3:

Thanks to everybody who answered my question.

Alsk’s answer met everything asked for in the bounty, and
was accepted. In multithreaded code, this solution would require
a separate cleanup thread.

I have added another answer where any exceptions during
cleanup are thrown by the thread that actually used the resource,
without need for a separate cleanup thread. If you are still
interested in this problem (it bothered me a lot), please
comment.

Smart pointers are a useful tool to manage resources safely. Examples
of such resources are memory, disk files, database connections, or
network connections.

// open a connection to the local HTTP port
boost::shared_ptr<Socket> socket = Socket::connect("localhost:80");

In a typical scenario, the class encapsulating the resource should be
noncopyable and polymorphic. A good way to support this is to provide
a factory method returning a shared pointer, and declare all
constructors non-public. The shared pointers can now be copied from
and assigned to freely. The object is automatically destroyed when no
reference to it remains, and the destructor then releases the
resource.

/** A TCP/IP connection. */
class Socket
{
public:
    static boost::shared_ptr<Socket> connect(const std::string& address);
    virtual ~Socket();
protected:
    Socket(const std::string& address);
private:
    // not implemented
    Socket(const Socket&);
    Socket& operator=(const Socket&);
};

But there is a problem with this approach. The destructor must not
throw, so a failure to release the resource will remain undetected.

A common way out of this problem is to add a public method to release
the resource.

class Socket
{
public:
    virtual void close(); // may throw
    // ...
};

Unfortunately, this approach introduces another problem: Our objects
may now contain resources which have already been released. This
complicates the implementation of the resource class. Even worse, it
makes it possible for clients of the class to use it incorrectly. The
following example may seem far-fetched, but it is a common pitfall in
multi-threaded code.

socket->close();
// ...
size_t nread = socket->read(&buffer[0], buffer.size()); // wrong use!

Either we ensure that the resource is not released before the object
is destroyed, thereby losing any way to deal with a failed resource
deallocation. Or we provide a way to release the resource explicitly
during the object’s lifetime, thereby making it possible to use the
resource class incorrectly.

There is a way out of this dilemma. But the solution involves using a
modified shared pointer class. These modifications are likely to be
controversial.

Typical shared pointer implementations, such as boost::shared_ptr,
require that no exception be thrown when their object’s destructor is
called. Generally, no destructor should ever throw, so this is a
reasonable requirement. These implementations also allow a custom
deleter function to be specified, which is called in lieu of the
destructor when no reference to the object remains. The no-throw
requirement is extended to this custom deleter function.

The rationale for this requirement is clear: The shared pointer’s
destructor must not throw. If the deleter function does not throw, nor
will the shared pointer’s destructor. However, the same holds for
other member functions of the shared pointer which lead to resource
deallocation, e.g. reset(): If resource deallocation fails, no
exception can be thrown.

The solution proposed here is to allow custom deleter functions to
throw. This means that the modified shared pointer’s destructor must
catch exceptions thrown by the deleter function. On the other hand,
member functions other than the destructor, e.g. reset(), shall not
catch exceptions of the deleter function (and their implementation
becomes somewhat more complicated).

Here is the original example, using a throwing deleter function:

/** A TCP/IP connection. */
class Socket
{
public:
    static SharedPtr<Socket> connect(const std::string& address);
protected:
    Socket(const std::string& address);
    virtual Socket() { }
private:
    struct Deleter;

    // not implemented
    Socket(const Socket&);
    Socket& operator=(const Socket&);
};

struct Socket::Deleter
{
    void operator()(Socket* socket)
    {
        // Close the connection. If an error occurs, delete the socket
        // and throw an exception.

        delete socket;
    }
};

SharedPtr<Socket> Socket::connect(const std::string& address)
{
    return SharedPtr<Socket>(new Socket(address), Deleter());
}

We can now use reset() to free the resource explicitly. If there is
still a reference to the resource in another thread or another part of
the program, calling reset() will only decrement the reference
count. If this is the last reference to the resource, the resource is
released. If resource deallocation fails, an exception is thrown.

SharedPtr<Socket> socket = Socket::connect("localhost:80");
// ...
socket.reset();

EDIT:

Here is a complete (but platform-dependent) implementation of the deleter:

struct Socket::Deleter
{
    void operator()(Socket* socket)
    {
        if (close(socket->m_impl.fd) < 0)
        {
            int error = errno;
            delete socket;
            throw Exception::fromErrno(error);
        }

        delete socket;
     }
};
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-14T23:29:49+00:00Added an answer on May 14, 2026 at 11:29 pm

    We need to store allocated resources somewhere (as it was already mentioned by DeadMG) 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.

    /** A TCP/IP connection. */
    class Socket
    {
    private:
        //store internally every allocated resource here
        static std::vector<boost::shared_ptr<Socket> > pool;
    public:
        static boost::shared_ptr<Socket> connect(const std::string& address)
        {
             //...
             boost::shared_ptr<Socket> 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<Socket>& 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->m_impl.fd) < 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& address);
    private:
        // not implemented
        Socket(const Socket&);
        Socket& operator=(const Socket&);
    };
    

    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.

    Now, more general solution:

    //forward declarations
    template<class Resource>
    boost::shared_ptr<Resource> make_shared_resource();
    template<class Resource>
    void cleanupAndReport(boost::function1<void,boost::shared_ptr<Resource> deallocator);
    
    //for every type of used resource there will be a template instance with a static pool
    template<class Resource>
    class pool_holder
    {
    private:
            friend boost::shared_ptr<Resource> make_shared_resource<Resource>();
            friend void cleanupAndReport(boost::function1<void,boost::shared_ptr<Resource>);
            static std::vector<boost::shared_ptr<Resource> > pool;
    };
    template<class Resource>
    std::vector<boost::shared_ptr<Resource> > pool_holder<Resource>::pool;
    
    template<class Resource>
    boost::shared_ptr<Resource> make_shared_resource()
    {
            boost::shared_ptr<Resource> res(new Resource);
            pool_holder<Resource>::pool.push_back(res);
            return res;
    }
    template<class Resource>
    void cleanupAndReport(boost::function1<void,boost::shared_ptr<Resource> > deallocator)
    {
        foreach(boost::shared_ptr<Resource>& res, pool_holder<Resource>::pool)
        {
            if(res.unique()) 
            {
                 deallocator(res);
            }
        } //foreach
    }
    //usage
            {
               boost::shared_ptr<A> a = make_shared_resource<A>();
               boost::shared_ptr<A> a2 = make_shared_resource<A>();
               boost::shared_ptr<B> b = make_shared_resource<B>();
               //...
            }
            cleanupAndReport<A>(deallocate_A);
            cleanupAndReport<B>(deallocate_B);
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Ask A Question

Stats

  • Questions 425k
  • Answers 425k
  • Best Answers 0
  • User 1
  • Popular
  • Answers
  • Editorial Team

    How to approach applying for a job at a company ...

    • 7 Answers
  • Editorial Team

    What is a programmer’s life like?

    • 5 Answers
  • Editorial Team

    How to handle personal stress caused by utterly incompetent and ...

    • 5 Answers
  • Editorial Team
    Editorial Team added an answer Its possible. The term you are missing is "Data Driven… May 15, 2026 at 12:26 pm
  • Editorial Team
    Editorial Team added an answer What is the mov sp, bp doing - where does… May 15, 2026 at 12:26 pm
  • Editorial Team
    Editorial Team added an answer It's kind of hard to figure out what you actually… May 15, 2026 at 12:26 pm

Trending Tags

analytics british company computer developers django employee employer english facebook french google interview javascript language life php programmer programs salary

Top Members

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.