MSVC std :: исключение не соответствует стандарту? - PullRequest
1 голос
/ 20 февраля 2012

Я реализовал класс исключений WINERR_EXCEPTION для выдачи описания времени выполнения GetLastError()!

И все заработало, как и ожидалось.Тогда я хотел устранить ненужные выделения.Для этого я реализовал промежуточный класс, который принимает и хранит const char*, который возвращается what().

Однако, когда я использую свой класс interim_exception, реализация std в MSVC (c ++ 11 Предварительный просмотр для разработчика):: исключение использует std::exception переменные-члены базового класса (вместо what()) для копирования строки описания.и я получаю "unknown exception" в качестве возвращаемого значения what().

стандарт говорит: :

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.

Это как-то связано со словом динамическое в постусловии (описание моего interim_exception не выделяется динамически) или это просто неправильная реализация?

std :: exception :: operator = (): msvc:

_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;
    }

мой код:

////////////////////////////////////////////////////////////////////////////////
// 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 );
    }
}

////////////////////////////////////////////////////////////////////////////////

мой тест:

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);
    }
}

1 Ответ

3 голосов
/ 21 февраля 2012

Два объекта «оба имеют динамический тип exception», если динамический тип обоих объектов равен exception и не является подтипом исключения.Таким образом, постусловие не применимо в вашем случае, так как динамический тип - WINERR_EXCEPTION, а не exception.

Если вы хотите, чтобы what() возвращал что-то отличное от значения по умолчанию, предоставленного std::exception(),тогда вам придется либо переопределить его самостоятельно, либо наследовать от того, что переопределяет его, например, типы исключений, определенные в <stdexcept>.(По крайней мере, так обстоит дело в стандарте C ++; я не знаю точно, как должны работать расширения Microsoft до std::exception, поэтому я не могу их комментировать).

...