Использование объекта формата C ++ Boost в качестве члена исключения

0

Я пытаюсь написать класс исключений, который нужно выбросить при сбое системного вызова. Исключение должно содержать сообщение разработчика и код errno, и what метод должен форматировать сообщение разработчика вместе с кодом ошибки. Способ C для форматирования - snprintf, но я стараюсь избегать этого. Я попытался определить член класса для исключения типа std::stringstream. Однако это не сработало, поскольку stringstream имеет закрытый конструктор копирования. В поисках альтернативы я узнал о объекте форматирования Boost. Я попытался использовать его и получил другую ошибку:

In file included from tun_device.cc:7:0:
system_error.h:9:7: error: looser throw specifier for ‘virtual SystemError::~SystemError()
 class SystemError : public exception
       ^
In file included from system_error.h:4:0,
                 from tun_device.cc:7:
/usr/include/c++/4.8/exception:64:13: error:   overriding ‘virtual std::exception::~exception() throw ()
     virtual ~exception() _GLIBCXX_USE_NOEXCEPT;

Способ решения этого заключался в том, чтобы определить мой собственный деструктор:

~SystemError() throw() {

}

Насколько я понимаю, эта строка указывает, что деструктор этого исключения не должен вызывать никаких исключений.

Здесь полный класс:

class SystemError : public exception
{
public:
    int m_errno;
    const char * m_message;

    SystemError(int err, const char * message) :
            fmt("%1%: %2%") {
        fmt % message % errno;
        m_errno = err;
        this->m_message = message;
    }

    const char * what() const throw(){
        return fmt.str().c_str();
    }

    ~SystemError()  throw() {

    }

private:
    format fmt;
};

У меня есть несколько вопросов:

  1. Прежде всего - я изобретаю колесо? Уже существует рекомендуемый способ C++ для обработки неудачных системных вызовов?

  2. Почему использование класса format в качестве члена исключения заставляет меня переопределить деструктор по умолчанию?

  3. Есть ли какая-то ошибка, о которой я должен знать сейчас, когда добавил своего деструктора?

  4. Есть ли способ достичь того, что я хочу использовать только в стандартной библиотеке C++?

  • 1
    Я хотел бы сделать fmt статическим, так как он может использоваться всеми экземплярами SystemError и выполнять форматирование внутри what() .
  • 0
    не добавляйте больше исключений, чем абсолютно необходимо. форматтер не нужен.
Показать ещё 3 комментария
Теги:
boost
custom-exceptions

1 ответ

3
Лучший ответ
  • Исключение можно обрабатывать с использованием стандартного класса исключений или создавать собственные классы, полученные из класса std :: exception. Наследование будет использоваться, когда вы захотите расширить уже доступную функциональность, доступную с помощью std :: exception. Таким образом, решение полностью зависит от того, как вы хотите создать свое приложение.

  • boost :: format не заставляет вас переопределять деструктор. Если вы заметили, что вы выходите из std :: exception и составляете boost :: format. std :: exception destructor объявляется как виртуальный и не имеет никакого эффекта броска.

    virtual ~exception() throw();

Когда вы отказываетесь от деструктора, компилятор неявно предоставляет деструктор, но этот деструктор не имеет свойства throw(), следовательно, компилирует ошибку:

format.cpp:5: error: looser throw specifier for âvirtual SystemError::~SystemError()â
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/exception:63: error:   overriding âvirtual std::exception::~exception() throw ()â

Когда вы предоставляете конструктор, но как:

   ~SystemError();    //since the base class std::exception has a destrutor with no throw, the child should also follow the same, and again in this case compile time error is received:


      format.cpp:25: error: looser throw specifier for âvirtual SystemError::~SystemError()â
    /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/exception:63: error:   overriding âvirtual std::exception::~exception() throw ()â

Чтобы устранить ошибку, SystemError должен определить деструктор следующим образом:

~SystemeError() throw();

Пример кода SSCCE:

  #include <iostream>
#include<boost/format.hpp>

class SystemError : public std::exception
{
  public:
    int m_errno;
    const char * m_message;

    SystemError(int err, const char * message) :
      fmt("%1%: %2%") {
        fmt % message % err;
        m_errno = err;
        this->m_message = message;
      }

    const char * what() const throw(){
      return fmt.str().c_str();
    }

    ~SystemError()  throw() {

    }

    //    ~SystemError()  {
    //
    //    }


  private:
    boost::format fmt;
};


int main(){

return 0;
}
  • Добавление деструктора - это как выполнение обязанностей ваших действий. Деструктор можно использовать для очистки памяти кучи, назначенной в классе. Отсутствие деструктора приведет к компилятору для обеспечения неявного деструктора, что может быть причиной проблем в конкретных случаях.

    Ошибка компиляции не будет получена, если класс в обсуждении имеет примитивные типы данных.

  • 0
    Поэтому, если я правильно понимаю, без члена format компилятор не создает деструктор для моего класса исключений, поскольку другие члены не являются классами и, следовательно, не должны быть уничтожены. Как только я добавляю первый член, который также является классом, компилятор автоматически создает деструктор для моего исключения, даже если я не определяю его сам. Деструктор, сгенерированный автоматически компилятором, не имеет природы «не выбрасывать», в отличие от деструктора-предка. Я прав?
  • 1
    Да, ваше понимание верно. Когда в вашем классе есть некоторые члены (boost :: format или std :: string), которые требуют очистки, компилятор выдает ошибку, если не указан правильный деструктор. Но если у вас есть примитивные типы данных, вы не получите ошибку. Деструктор с типами POD или без элементов данных становится тривиальным (ссылка en.cppreference.com/w/cpp/language/destructor )

Ещё вопросы

Сообщество Overcoder
Наверх
Меню