使用 C++ Boost 的格式对象作为异常成员

Using C++ Boost's format object as an exception member

本文关键字:异常 成员 对象 格式 C++ Boost 使用      更新时间:2023-10-16

我试图编写一个异常类,需要在系统调用失败时抛出。异常应该有一个开发人员消息和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++库?

  • Exception可以使用标准的Exception类来处理,也可以从std:: Exception类派生出自己的类来处理。当您想要扩展使用std::exception已经可用的功能时,可以使用继承。所以这个决定完全取决于你想如何设计你的应用程序。

  • boost::format不会强制你重写析构函数。如果您注意到您正在从std::exception派生并组合boost::format。std::exception析构函数声明为虚函数,具有无抛出性质。

<>之前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 ();//由于基类std::exception有一个没有throw的析构函数,子类也应该遵循相同的析构函数,并且在这种情况下再次收到编译时错误:format.cpp:25: error: loose throw指定符::~SystemError() /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/exception:63: error: override: virtual std::exception::~exception() throw () 之前要解决这个错误,systememerror应该定义一个析构函数:

~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;
}
  • 添加析构函数就像是为你的行为承担责任。析构函数可用于清除类中分配的任何堆内存。缺少析构函数将导致编译器提供隐式析构函数,这可能在特定情况下导致问题。

    如果所讨论的类具有基本数据类型,则不会收到编译错误。