Класс исключения с конструктором char *

Я натолкнулся на следующий код на VS2008

if (!CreateProcess( NULL,
                    const_cast<LPWSTR>(ss.str().c_str()),
                    NULL,
                    NULL,
                    FALSE,
                    CREATE_NO_WINDOW|NORMAL_PRIORITY_CLASS,
                    NULL,
                    NULL,
                    &si,
                    &pi))
{
    throw   std::exception("Unable to format Device");
}

Теперь я переношу код в mingw gcc, и я получаю ошибку

error: no matching function for call to 'std::exception::exception(const char [23])'

Исследуя проблему, я заметил, что Visual Studio имеет исключение файла, которое имеет класс исключения и принимает char *. Некоторые определения выглядят так:

   __CLR_OR_THIS_CALL exception();
    __CLR_OR_THIS_CALL exception(const char *const&);
    __CLR_OR_THIS_CALL exception(const char *const&, int);
    __CLR_OR_THIS_CALL exception(const exception&);
    exception& __CLR_OR_THIS_CALL operator=(const exception&);
    virtual __CLR_OR_THIS_CALL ~exception();
    virtual const char * __CLR_OR_THIS_CALL what() const;

Мой вопрос: как мне обойти эту проблему сборки в mingw gcc? Должен ли я создать новый класс, который наследуется от std :: runtime_error и вместо этого бросает это?

Ответ 1

Мнение играет здесь роль. Проблема в том, что std::exception не имеет конструктора, который принимает строковый аргумент; это расширение MSVC. Я вижу два пути:

  1. Не передавать строковый аргумент
  2. Не используйте std::exception

Первый случай прост; просто используйте

throw std::exception();

Недостатком является то, что вы не получите описательное сообщение об ошибке.

Если сообщение об ошибке важно, использование std::exception напрямую не является опцией. В этом случае вы можете использовать либо std::logic_error либо std::runtime_error, которые наследуют std::exception и имеют конструкторы, принимающие строковый аргумент, поэтому

throw std::runtime_error("Unable to format Device");

может решить проблему. catch которые поймали std::exception, также поймают std::runtime_error. Однако есть одна потенциальная проблема: catch clauses, которые поймают std::runtime_error, не поймали бы std::exception но поймают это.

Это похоже на крошечный случай, и вполне возможно, что это не проблема для вас. Если, однако, существует вероятность, что в стеке вызовов есть предложение catch, которое ловит std::runtime_error но не должно улавливать исключение, созданное этим кодом, вы можете получить свой собственный класс исключения из std::exception, который принимает строковый аргумент. Поскольку класс является новым, он не будет улавливаться существующими предложениями catch. Например:

class descriptive_exception : public std::exception {
public:
  descriptive_exception(std::string const &message) : msg_(message) { }
  virtual char const *what() const noexcept { return msg_.c_str(); }

private:
  std::string msg_;
}

А потом

throw descriptive_exception("Unable to format Device");

Это, возможно, не очень красиво, и маловероятно, что это необходимо, поэтому более вероятным решением является использование std::runtime_error или std::logic_error (или класс, полученный из одного из них).

Является ли std::logic_error или std::runtime_error более уместным, не очень понятно; в этом случае я, вероятно, поеду с std::runtime_error потому что ошибка не кажется даже теоретически предсказуемой, но учитывая, что std::domain_error и std::future_error получают из std::logic_error, это не будет полностью неуместно в этой иерархии. Это, я думаю, вопрос мнения.