clean-up code before throwing an exception may also throw

Discussion in 'C++' started by Eric Lilja, Jan 5, 2005.

  1. Eric Lilja

    Eric Lilja Guest

    Hello, in my program I have a function (pseudo code):

    void start_mysql_service()
    {
    obtain handle

    start mysql service using handle

    if start fails close handle and throw an exception containing error
    description

    else just close handle and return
    }

    So no matter if the service is successfully started or not, the handle needs
    to be closed to prevent leakage. But the function that closes the handle may
    also throw. How should I handle that? catch the close-handle-exception in
    start_mysql_service()? Right now I don't catch anything in the
    start_mysql_service() function so if it fails to start the service it
    prepares to throw an exception, that exception never gets thrown if it the
    close handle functions throws. I don't want one error hiding another one.
    The real code looks like this and it's ugly (and contains some platform
    specific material, sorry about that):
    void
    start_mysql_service()
    {
    /* May throw an exception. */
    SC_HANDLE mysql_service = get_mysql_service_handle();

    if(!StartService(mysql_service, 0, NULL))
    {
    /* May throw an exception and if it does I never get to throw */
    /* the exception indicating that StartService() failed. */
    close_service_handle(mysql_service);

    /* TODO: Obtain more precise cause of error if possible using
    GetLastError() and FormatMessage(). */
    throw runtime_error("StartService() failed.");
    }

    /* May throw an exception. */
    close_service_handle(mysql_service);
    }


    Any ideas how to restructure this into nicer-looking code and solving the
    problem of one error hiding another one?

    / E
    Eric Lilja, Jan 5, 2005
    #1
    1. Advertising

  2. Eric Lilja

    red floyd Guest

    Eric Lilja wrote:
    > Hello, in my program I have a function (pseudo code):
    >
    > void start_mysql_service()
    > {
    > obtain handle
    >
    > start mysql service using handle
    >
    > if start fails close handle and throw an exception containing error
    > description
    >
    > else just close handle and return
    > }
    >


    > So no matter if the service is successfully started or not, the handle needs
    > to be closed to prevent leakage. But the function that closes the handle may
    > also throw. How should I handle that? catch the close-handle-exception in
    > start_mysql_service()? Right now I don't catch anything in the
    > start_mysql_service() function so if it fails to start the service it
    > prepares to throw an exception, that exception never gets thrown if it the
    > close handle functions throws. I don't want one error hiding another one.
    > The real code looks like this and it's ugly (and contains some platform
    > specific material, sorry about that):


    Use nested try catch blocks

    > void
    > start_mysql_service()
    > {
    > /* May throw an exception. */
    > SC_HANDLE mysql_service = get_mysql_service_handle();
    >
    > if(!StartService(mysql_service, 0, NULL))
    > {
    > /* May throw an exception and if it does I never get to throw */
    > /* the exception indicating that StartService() failed. */

    try
    {
    > close_service_handle(mysql_service);

    }
    catch (...)
    {
    // we don't care about this exception, we want
    // to say what that StartService failed, so we
    // catch and ignore it.
    }
    >

    // note: this TODO should probably go before the call to
    // call to close_service_handle(), so that any error in c_s_h()
    // doesn't mask the results from StartService()
    > /* TODO: Obtain more precise cause of error if possible using
    > GetLastError() and FormatMessage(). */
    > throw runtime_error("StartService() failed.");
    > }
    >
    > /* May throw an exception. */
    > close_service_handle(mysql_service);
    > }
    >
    >
    > Any ideas how to restructure this into nicer-looking code and solving the
    > problem of one error hiding another one?
    >
    > / E
    >
    >
    red floyd, Jan 5, 2005
    #2
    1. Advertising

  3. "Eric Lilja" <> skrev i en meddelelse
    news:crhska$82b$...
    > Hello, in my program I have a function (pseudo code):
    >
    > void start_mysql_service()
    > {
    > obtain handle
    >
    > start mysql service using handle
    >
    > if start fails close handle and throw an exception containing error
    > description
    >
    > else just close handle and return
    > }


    First off, the handle should be wrapped into a class providing RAII.

    Now your code is reduced into this simpler:

    class raii_handle
    {
    public:
    //constructor: obtains handle
    //destructor: releases handle
    };

    void start_mysql_service()
    {
    handle_class hc(); // constructor allocates

    start mysql service using handle
    }


    >
    > So no matter if the service is successfully started or not, the handle
    > needs to be closed to prevent leakage. But the function that closes the
    > handle may also throw. How should I handle that? catch the
    > close-handle-exception in start_mysql_service()? Right now I don't catch
    > anything in the


    I do not see why the closing the handle could trigger an exception:
    releasing a ressource ought to always be safe. But assuming your statement
    is true and the close can't be ignored, i would augment the handle-class to
    have a close method:


    class raii_handle
    {
    public:
    //constructor: obtains handle
    //destructor: releases handle
    ~raii_handle()
    {
    try
    {
    close();
    }
    catch (...)
    {
    // either assert or log error - or just plainly ignore it.
    // in places where the errorcheck is needed, you can do an
    // explicit close
    }
    }
    void close(); // could throw
    };

    /Peter
    Peter Koch Larsen, Jan 5, 2005
    #3
  4. Eric Lilja

    Eric Lilja Guest

    "Peter Koch Larsen" <> wrote in message
    news:F4%Cd.80603$...
    >
    > "Eric Lilja" <> skrev i en meddelelse
    > news:crhska$82b$...
    >> Hello, in my program I have a function (pseudo code):
    >>
    >> void start_mysql_service()
    >> {
    >> obtain handle
    >>
    >> start mysql service using handle
    >>
    >> if start fails close handle and throw an exception containing error
    >> description
    >>
    >> else just close handle and return
    >> }

    >
    > First off, the handle should be wrapped into a class providing RAII.
    >
    > Now your code is reduced into this simpler:
    >
    > class raii_handle
    > {
    > public:
    > //constructor: obtains handle
    > //destructor: releases handle
    > };
    >
    > void start_mysql_service()
    > {
    > handle_class hc(); // constructor allocates


    You mean handle_class hc; I presume. The above declares a function as you
    know, a silly typo I've made myself numerous times.

    >
    > start mysql service using handle
    > }
    >
    >
    >>
    >> So no matter if the service is successfully started or not, the handle
    >> needs to be closed to prevent leakage. But the function that closes the
    >> handle may also throw. How should I handle that? catch the
    >> close-handle-exception in start_mysql_service()? Right now I don't catch
    >> anything in the

    >
    > I do not see why the closing the handle could trigger an exception:
    > releasing a ressource ought to always be safe. But assuming your statement
    > is true and the close can't be ignored, i would augment the handle-class
    > to have a close method:
    >


    Well, it can fail at least and I (the programmer) want to be notified of
    such errors so I'm making close_service_handle() throw. I like the idea of
    wrapping the handle in a class..it gets more robust because you cannot
    forget to close the handle, the destructor will do it for you. But if the
    destructor fails to close the handle I want to know somehow..an exception is
    not a good idea I guess..I like the logging idea you proposed.

    >
    > class raii_handle
    > {
    > public:
    > //constructor: obtains handle
    > //destructor: releases handle
    > ~raii_handle()
    > {
    > try
    > {
    > close();
    > }
    > catch (...)
    > {
    > // either assert or log error - or just plainly ignore it.
    > // in places where the errorcheck is needed, you can do an //
    > explicit close
    > }
    > }
    > void close(); // could throw
    > };
    >
    > /Peter
    >


    Thanks for your help

    / Eric
    Eric Lilja, Jan 6, 2005
    #4
  5. "Eric Lilja" <> skrev i en meddelelse
    news:crhv7a$8ol$...
    >
    > "Peter Koch Larsen" <> wrote in message
    > news:F4%Cd.80603$...
    >>
    >> "Eric Lilja" <> skrev i en meddelelse
    >> news:crhska$82b$...



    [snip]

    >> Now your code is reduced into this simpler:
    >>
    >> class raii_handle
    >> {
    >> public:
    >> //constructor: obtains handle
    >> //destructor: releases handle
    >> };
    >>
    >> void start_mysql_service()
    >> {
    >> handle_class hc(); // constructor allocates

    >
    > You mean handle_class hc; I presume. The above declares a function as you
    > know, a silly typo I've made myself numerous times.


    Of course.
    >



    [snip]

    >>
    >> I do not see why the closing the handle could trigger an exception:
    >> releasing a ressource ought to always be safe. But assuming your
    >> statement is true and the close can't be ignored, i would augment the
    >> handle-class to have a close method:
    >>

    >
    > Well, it can fail at least and I (the programmer) want to be notified of
    > such errors so I'm making close_service_handle() throw. I like the idea of
    > > wrapping the handle in a class..it gets more robust because you cannot

    > forget to close the handle, the destructor will do it for you. But if the
    > destructor fails to close the handle I want to know somehow..an exception
    > is not a good idea I guess..I like the logging idea you proposed.
    >


    Right. But do examine WHY the call might fail. I've never seen errors of a
    type that couldn't either be ignored or replaced by an assertion.


    [snip]
    Peter Koch Larsen, Jan 8, 2005
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kerri
    Replies:
    2
    Views:
    12,993
    Kevin Spencer
    Oct 27, 2003
  2. VisionSet
    Replies:
    51
    Views:
    4,256
    Tony Morris
    Jul 14, 2004
  3. Replies:
    15
    Views:
    7,482
    Roedy Green
    Sep 8, 2005
  4. Jacek Dziedzic
    Replies:
    13
    Views:
    513
  5. Replies:
    3
    Views:
    588
Loading...

Share This Page