简体   繁体   English

如何在异常中抛出有意义的数据?

[英]How to throw meaningful data in exceptions?

I would like to throw exceptions with meaningful explanation (socket handle, process id, network interface index, ...) ! 我想抛出有意义解释的异常(套接字句柄,进程ID,网络接口索引......)! I thought of using variable arguments worked fine but lately I figured out it's impossible to extend the class in order to implement other exception types. 我想使用变量参数工作正常,但最近我发现,为了实现其他异常类型,不可能扩展类。 So I figured out using an std::ostreamstring as a an internal buffer to deal with formatting ... but doesn't compile! 所以我想出了使用std :: ostreamstring作为内部缓冲区来处理格式化......但是没有编译! I guess it has something to deal with copy constructors. 我想它有一些东西可以处理复制构造函数。 Anyhow here is my piece of code: 无论如何这是我的代码片段:

 class Exception: public std::exception {
public:
  Exception(const char *fmt, ...);
  Exception(const char *fname,
            const char *funcname, int line, const char *fmt, ...);
  //std::ostringstream &Get() { return os_ ; }
  ~Exception() throw();
  virtual const char *what() const throw();

protected: char err_msg_[ERRBUFSIZ]; //std::ostringstream os_; };

The variable argumens constructor can't be inherited from! 变量argumens构造函数不能继承! this is why I thought of std::ostringstream! 这就是为什么我想到了std :: ostringstream! Any advice on how to implement such approach ? 关于如何实施这种方法的任何建议?

It is a bit awkward to pass ... arguments, but possible. 通过...论证有点尴尬,但可能。 You need first to convert them to va_list . 您首先需要将它们转换为va_list So, for your derived class to be able to pass the format and the arguments to its base class something like the following can be done: 因此,为了使您的派生类能够将格式和参数传递给其基类,可以执行以下操作:

class Exception: public std::exception {
public:
  Exception(const char *fmt, ...)
  {
    va_list ap;
    va_start(ap, fmt);
    this->init(fmt, ap);
    va_end(ap);
  }

  virtual const char *what() const throw();

protected:
  Exception(); // for use from derived class's ctor

  void init(char const* fmt, va_list, ap)
  {
    vsnprintf(err_msg_, sizeof err_msg_, fmt, ap);
  }

  char err_msg_[ERRBUFSIZ];
};

struct Exception2 : Exception
{
  Exception2(const char *fmt, ...)
  {
    va_list ap;
    va_start(ap, fmt);
    this->init(fmt, ap);
    va_end(ap);
  }
};

I presume you mean the problem is that ostringstream isn't copy constructible. 我认为你的意思是问题是ostringstream不是可复制构造的。 If I understand correctly, how about making ostringstream member be a pointer like std/boost::shared_ptr ? 如果我理解正确,那么如何使ostringstream成员成为像std/boost::shared_ptr这样的指针? For example: 例如:

#include <exception>
#include <sstream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

struct E : std::exception {
  boost::shared_ptr< std::ostringstream > os_;
  mutable std::string s_;
  std::ostringstream &Get() { return *os_; } 
  const char *what() const throw() {
    s_ = os_->str();
    return s_.c_str();
  }
  E() : os_( boost::make_shared< std::ostringstream >() ) {}
  ~E() throw() {}
};

int main()
{
  try {
    E e;
    e.Get() << "x";
    throw e;
  }
  catch ( std::exception const& e ) {
    cout<< e.what() <<endl;
  }
}

Hope this helps. 希望这可以帮助。

Usually, the best solution is to define dedicated exception types for different exceptions. 通常,最佳解决方案是为不同的异常定义专用的异常类型。 Your SocketException type would accept a socket handle, etcetera. 您的SocketException类型将接受套接字句柄等。 This eliminates the need for a vararg ... argument in the ctor. 这消除了在ctor中对vararg ...参数的需要。

Also, you wouldn't need a std::ostringstream os_ member. 此外,您不需要std::ostringstream os_成员。 An ostringstream object is commonly used to format text, but not to store the result. ostringstream对象通常用于格式化文本,但不用于存储结果。 For that purpose, use an ordinary std::string . 为此,请使用普通的std::string

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM