How to throw meaningful data in exceptions?
I would like to throw exceptions with meaningful explanation (socket handle, process id, network interface index, ...) ! 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! 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 const开发者_运维问答ructor can't be inherited from! this is why I thought of 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
. 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.
If I understand correctly,
how about making ostringstream
member be a pointer like 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. This eliminates the need for a vararg ...
argument in the ctor.
Also, you wouldn't need a std::ostringstream os_
member. An ostringstream
object is commonly used to format text, but not to store the result. For that purpose, use an ordinary std::string
.
精彩评论