Why can't I catch this exception?

I want to create several types of exceptions that are thrown from std :: runtime_error, and I want them to have a function of type stringstream. So I created an exception class which is std::stringstream and which comes from std::runtime_error :

 template<typename T> class error_stream : public std::runtime_error { public: error_stream() : std::runtime_error(""), ss(std::make_shared<std::basic_stringstream<T>> ()) { } ~error_stream() throw() { } template <typename T> error_stream & operator << (const T & t) { *ss << t; return *this; } virtual const char * what() const throw() { get_str(s_, ss->str()); return s_.c_str(); } protected: template <typename T> void get_str(std::basic_string<char> & s_, const std::basic_string<T> & str) const { s_ = str; } template<> void get_str(std::basic_string<char> & s_, const std::basic_string<wchar_t> & str) const { std::basic_string<char> ret(str.begin(), str.end()); s_ = ret; } protected: std::shared_ptr<std::basic_stringstream<T>> ss; mutable std::basic_string<char> s_; }; 

And I created a more specific type of exception, which in turn stems from this error_stream exception:

 template<typename T> class w32file_exception : public w32utils::error_stream<T> { public: w32file_exception() : error_stream<T>() {} }; 

However, I came across something that I don’t understand here, because when I throw a w32file_exception , I really can only catch it as the parent error_stream . Can anyone see what I'm doing wrong?

  try { throw w32file_exception<char>() << "test"; } catch ( w32file_exception<char> & e ) { ASSERT_PASSED; } catch ( error_stream<char> & e ) { std::cout << e.what() << std::endl; // Why do I end up here? } 
+6
source share
1 answer

What does your throw look like? Do you use operator<< before calling throw, for example:

 throw w32file_exception<T>() << "fooobar"; 

Then the answer is that your operator<< returns error_stream and no w32file_exception , therefore the type of the generated exception is error_stream .

You can solve this problem as follows:

 template<typename T, typename DERIVED> class error_stream : public std::runtime_error { public: // ... template <typename U> DERIVED & operator << (const T & t) { *ss << t; return static_cast<DERIVED&>(*this); } // ... }; 

But then you lose the ability to catch every error_stream exception, because this is a new type for each DERIVED type.

+13
source

Source: https://habr.com/ru/post/916850/


All Articles