Reputation: 3929
I implemented an exception class WINERR_EXCEPTION
for throwing runtime description of GetLastError()
!
And it worked as expected.
Then I wanted to eliminate the unnecessary allocations.
For that I implemented an interim class that takes and stores a const char*
which is returned by what()
.
However when I use my interim_exception class the MSVC (c++11 developer preview) implementation of std::exception uses the std::exception
baseclass member-variables (instead of what()
) to copy the description-string.
and I get "unknown exception"
as the return value of what()
.
standard says :
exception& operator=(const exception& rhs) noexcept;
Effects: Copies an exception object.
Postcondition: If *this and rhs both have dynamic type exception then strcmp(what(), rhs.what()) shall equal 0.
Has this something to do with the word dynamic in the Postcondition (my interim_exception's description is not dynamically allocated) or is this just a wrong implementation ?
msvc's std::exception::operator= () :
_EXCEPTION_INLINE exception& __CLR_OR_THIS_CALL exception::operator=(const exception& _That)
{
if (this != &_That)
{
_Tidy(); // resets members
if (_That._Mydofree) // NB. This prevents my intentions (evals to false)
{
_Copy_str(_That._Mywhat);
}
else
{
_Mywhat = _That._Mywhat;
}
}
return *this;
}
my code :
////////////////////////////////////////////////////////////////////////////////
// file : TstThrow.h
// purpose : implementation of class WINERR_EXCEPTION
////////////////////////////////////////////////////////////////////////////////
//
#include <windows.h>
#include <exception>
#include <stdexcept>
////////////////////////////////////////////////////////////////////////////////
namespace
{
// class interim_exception to avoid unnecessary allocations
class interim_exception
: public std::exception
{
public:
// override member : what() const
const char * what() const
//_EXCEPTION_INLINE virtual const char * __CLR_OR_THIS_CALL what() const
{ return m_What; }
interim_exception( const char* szWhat )
:m_What( szWhat ? szWhat : "" ) {}
private:
const char* m_What;
};
}
////////////////////////////////////////////////////////////////////////////////
class WINERR_EXCEPTION
: public std::exception
{
public:
DWORD ErrNo () const { return m_ErrNo; }
public:
explicit WINERR_EXCEPTION ( DWORD dwErrNo );
inline exception& operator= ( const exception& that )
{
exception::operator= ( that );
return (*this);
}
inline exception& operator= ( const char* szWhat )
{
operator= ( std::exception( szWhat )); /* this works OK */
// exception::operator= ( std::exception( szWhat )); /* this works OK */
// exception::operator= (interim_exception( szWhat )); /* this doesn't work */
// operator= (interim_exception( szWhat )); /* this doesn't work */
return (*this);
}
private:
DWORD m_ErrNo;
};
////////////////////////////////////////////////////////////////////////////////
WINERR_EXCEPTION::WINERR_EXCEPTION ( DWORD dwErrNo )
:m_ErrNo (dwErrNo) //exception("") ,
{
DWORD dwFrmtFlags (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER);
dwFrmtFlags |= FORMAT_MESSAGE_IGNORE_INSERTS;
dwFrmtFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK; // no newlines
LPSTR pBuffer (nullptr);
if (! ::FormatMessageA( dwFrmtFlags ,nullptr
,dwErrNo ,0 ,(LPSTR)&pBuffer ,0 ,nullptr ))
{
dwErrNo = GetLastError();
if (dwErrNo == ERROR_MR_MID_NOT_FOUND)
operator= ( WINERR_EXCEPTION( dwErrNo ).what() );
else
operator= ( "Substituted Error Message :\n\t"
"Could not allocate buffer for ORIGINAL Error Message\n" );
}
else
{
operator= ( pBuffer );
LocalFree( pBuffer );
}
}
////////////////////////////////////////////////////////////////////////////////
my test :
void TstThrow ()
{
for ( DWORD dwErr = ERROR_SUCCESS; dwErr < 200; ++dwErr )
{
SetLastError( dwErr );
try
{
throw ::WINERR_EXCEPTION( GetLastError() );
}
catch (const ::WINERR_EXCEPTION& werr)
{
::WINERR_EXCEPTION err ( werr ); // test for copying of object !
std::cout << std::setw(4) << werr.ErrNo() << " :"<< werr.what() << std::endl;
}
if ((dwErr % 100) == 0)
Sleep(1500);
}
}
Upvotes: 1
Views: 1335
Reputation: 254451
The two objects "both have dynamic type exception
" if the dynamic type of both objects is exception
, and not a subtype of exception. So the postcondition doesn't apply in your case, since the dynamic type is WINERR_EXCEPTION
, not exception
.
If you want what()
to return something other than the default provided by std::exception()
, then you'll have to either override it yourself, or inherit from something that overrides it, such as the exception types defined in <stdexcept>
. (At least that's the case in Standard C++; I don't know exactly how Microsoft's extensions to std::exception
are supposed to work, so I can't comment on them).
Upvotes: 3