I'm trying to develop an Exception class, that allows collecting relevant data stream-style.
Following Custom stream to method in C++? I've extended my own class:
class NetworkException : public std::exception, public std::ostream
to pick the error data from a stream and then return whatever it acquired through .what()
.
Then I tried something like this:
try {
ssize_t ret = send(sock, headBuffer, headLength, MSG_MORE);
if (ret <= 0) throw NetworkException() << "Error sending the header: " << strerror(errno);
// much more communication code
} catch (NetworkException& e) {
connectionOK = false;
logger.Warn("Communication failed: %s",e.what());
}
But the compiler produces an error:
HTTPClient.cpp:246:113: error: use of deleted function 'std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)'
(that's the line with the throw
.)
I realize streams don't have copy constructors, but I thought catching a reference instead of the object would suffice. How can I overcome this - can I throw an object that 'swallows' a stream?
You cannot copy object containing stream object using default copy constructor, but you can write your own copy constructor that will copy content of stream.
#include <iostream>
#include <sstream>
struct StreamableError : public std::exception {
template <typename T>
StreamableError& operator << (T rhs) {
innerStream << rhs;
return *this;
}
StreamableError() = default;
StreamableError(StreamableError& rhs) {
innerStream << rhs.innerStream.str();
}
virtual const char* what() const noexcept {
str = innerStream.str(); //this can throw
return str.c_str();
}
private:
std::stringstream innerStream;
mutable std::string str;
};
int main() {
try {
throw StreamableError() << "Formatted " << 1 << " exception.";
} catch (std::exception& e) {
std::cout << e.what() << std::endl;
}
}
Solution above is not perfect. If str = innerStream.str()
throws then std::terminate
will be called. If you want to make what
method to be trully noexcept
then you have two choices:
str
variable inside copy constructor. Then you will not be able to call what
method to obtain exception message before you throw.str
variable inside copy constructor and <<
operator. In this case you will be able to obtain exception message before throw, but you will be copying message each time operator is called, which may be an overkill.