what() method of exceptions derived form std::exception

Discussion in 'C++' started by Boogie El Aceitoso, Nov 4, 2003.

  1. Hi,

    I have an exception class for winapi errors (returns a formated error mesage,
    usign ::GetLastError() et al, with what()).

    It looks like this:

    class WinapiException : public std::exception
    {
    public:
    WinapiException(const std::string & extraInfo);
    virtual const char* what() const throw();
    private:
    std::string _extraInfo;
    };

    WinapiException::WinapiException(const std::string & extraInfo)
    :_extraInfo(extraInfo)
    {
    // Nothing
    }

    The problem is the what() method. Mine looks like this:

    const char* WinapiException::what() const throw()
    {
    std::string rc;

    rc = typeid(this).name();

    // errorString formats the winapi error message and returns an std::string
    rc += "GetLastError reports:\n" + errorString:):GetLastError());

    if( _extraInfo.size() > 0)
    {
    rc += "\nExtra Info:\n" + _extraInfo;
    }
    else
    {
    rc += "\nNo extra info available.";
    }

    return rc.c_str(); // here's the problem!!!
    }

    The what() returns a const char* that points to something that has already
    been destroyed and freed.

    What's the best solution for this? O:)
    Boogie El Aceitoso, Nov 4, 2003
    #1
    1. Advertising

  2. On Tue, 04 Nov 2003 11:57:22 +0100, Boogie El Aceitoso
    <> wrote:

    >
    > return rc.c_str(); // here's the problem!!!
    > }
    >
    >The what() returns a const char* that points to something that has already
    >been destroyed and freed.
    >
    >What's the best solution for this? O:)


    I am not sure that you have given us enough information to confidently
    state a best solution. I can see several ways out.

    1. You could make rc a non-static data member of your class.
    2. You could declare rc static in the member function.
    3. You could declare rc a static data member of the class.
    4. You could allocate a dynamic array for the array. But that is
    almost always more trouble than its worth. Who deletes the array?

    Anyway, there are four ways of handling the problem. I might make it
    a data member (static or non-static).
    --

    Best wishes,

    Bob
    Robert W Hand, Nov 4, 2003
    #2
    1. Advertising

  3. Boogie El Aceitoso

    Ron Natalie Guest

    "Boogie El Aceitoso" <> wrote in message news:...

    >
    > The what() returns a const char* that points to something that has already
    > been destroyed and freed.
    >

    The easiest way is to keep the data in a string which is a member of the exception
    object.

    There are two ways you could do this:

    1. You could just add another member "what_string" and fill it in rather than "rc"
    in your what() function (you could even notice if this had been set and avoid recomputing
    the string on subsuequent calls to what()).

    2. The WinapiException could do what you now do in the what() function and store only the
    "whatString" rather than the extrainfo in the object.
    Ron Natalie, Nov 4, 2003
    #3
  4. Boogie El Aceitoso <> wrote in message news:<>...
    >
    > I have an exception class for winapi errors (returns a formated error mesage,
    > usign ::GetLastError() et al, with what()).
    >
    > It looks like this:
    >
    > class WinapiException : public std::exception
    > {
    > public:
    > WinapiException(const std::string & extraInfo);
    > virtual const char* what() const throw();
    > private:
    > std::string _extraInfo;
    > };
    >
    > WinapiException::WinapiException(const std::string & extraInfo)
    > :_extraInfo(extraInfo)
    > {
    > // Nothing
    > }
    >
    > The problem is the what() method. Mine looks like this:
    >
    > const char* WinapiException::what() const throw()
    > {
    > std::string rc;
    >
    > rc = typeid(this).name();
    >
    > // errorString formats the winapi error message and returns an std::string
    > rc += "GetLastError reports:\n" + errorString:):GetLastError());
    >
    > if( _extraInfo.size() > 0)
    > {
    > rc += "\nExtra Info:\n" + _extraInfo;
    > }
    > else
    > {
    > rc += "\nNo extra info available.";
    > }
    >
    > return rc.c_str(); // here's the problem!!!
    > }
    >
    > The what() returns a const char* that points to something that has already
    > been destroyed and freed.


    The answer is simple: have what() return something that isn't already
    destroyed and freed.

    WinapiException::WinapiException(const std::string & extraInfo)
    :_extraInfo(typeid(this).name())
    {
    // errorString formats the winapi error message and returns an
    std::string
    _extraInfo += "GetLastError reports:\n" +
    errorString:):GetLastError());

    if (extraInfo.size() > 0)
    {
    _extraInfo += "\nExtra Info:\n" + extraInfo;
    }
    else
    {
    _extraInfo += "\nNo extra info available.";
    }
    }

    const char* WinapiException::what() const throw()
    {
    return _extraInfo.c_str();
    }

    This has the added advantage that ::GetLastError() will be called at
    the point when the exception is thrown, rather than later when the
    exception is reported and its value may have been affected by
    intervening system calls.

    --
    Stephen M. Webb
    Stephen M. Webb, Nov 4, 2003
    #4
  5. Boogie El Aceitoso wrote:
    > ...
    > I have an exception class for winapi errors (returns a formated error mesage,
    > usign ::GetLastError() et al, with what()).
    >
    > It looks like this:
    >
    > class WinapiException : public std::exception
    > {
    > public:
    > WinapiException(const std::string & extraInfo);
    > virtual const char* what() const throw();
    > private:
    > std::string _extraInfo;
    > };
    >
    > WinapiException::WinapiException(const std::string & extraInfo)
    > :_extraInfo(extraInfo)
    > {
    > // Nothing
    > }
    > ...


    Just to add something less relevant to other people's replies:

    The above definition of 'WinapiException' class is ill-formed. Your
    class 'WinapiException' contains a subobject of type 'std::string'. The
    'std::string's destructor has no exception specification (allows all
    types of exceptions), which immediately means that the implicitly
    declared destructor of class 'WinapiException' will also allow all types
    of exceptions (see 15.4/13). At the same time the virtual destructor of
    'std::exception' is declared with 'throw()' exception specification (no
    exceptions allowed). According to 15.4/3, the above definition of
    'WinapiException' is ill-formed, since the declaration of virtual
    function 'WinapiException::~WinapiException' is less restrictive than
    the exception specification of base class' virtual function it overrides
    ('std::exception::~exception'). (See also an example in 15.4/13, which
    is similar to yours in this respect.)

    It is very likely that your compiler accepts the above code. But don't
    be surprised if one day it will start complaining.

    --
    Best regards,
    Andrey Tarasevich
    Andrey Tarasevich, Nov 4, 2003
    #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. Peter Jansson
    Replies:
    5
    Views:
    6,294
    Ivan Vecerina
    Mar 17, 2005
  2. Paul Miller
    Replies:
    3
    Views:
    1,014
    Alex Martelli
    Nov 12, 2003
  3. Vinu
    Replies:
    4
    Views:
    353
    Jim Langston
    Jul 7, 2005
  4. Replies:
    1
    Views:
    393
    myork
    May 23, 2007
  5. Replies:
    1
    Views:
    385
    Victor Bazarov
    May 23, 2007
Loading...

Share This Page