How to simulate an internal exception in C ++

Basically I want to simulate a .NET Exception.InnerException in C ++. I want to catch an exception from the bottom layer and wrap it with another exception and drop it to the upper level again. The problem here is that I do not know how to wrap an exception that is excluded from another exception.

struct base_exception : public std::exception { std::exception& InnerException; base_exception() : InnerException(???) { } // <---- what to initialize with base_exception(std::exception& innerException) : InnerException(innerException) { } }; struct func1_exception : public base_exception { const char* what() const throw() { return "func1 exception"; } }; struct func2_exception : public base_exception { const char* what() const throw() { return "func2 exception"; } }; void func2() { throw func2_exception(); } void func1() { try { func2(); } catch(std::exception& e) { throw func2_exception(e); // <--- is this correct? will the temporary object will be alive? } } int main(void) { try { func1(); } catch(base_exception& e) { std::cout << "Got exception" << std::endl; std::cout << e.what(); std::cout << "InnerException" << std::endl; std::cout << e.InnerException.what(); // <---- how to make sure it has inner exception ? } } 

In the code list above, I'm not sure how to initialize the InnerException member when there is no internal exception. Also, I'm not sure if the temporary object that is called from func1 will be saved, even after func2 throw?

+4
source share
5 answers

You should also take a look at boost exception for an alternative packaging solution.

+3
source

Also, I'm not sure if the temporary object that is thrown from func1 will persist even after throwing func2?

Not. If you do not throw; exception with throw; . This can be implemented if you allow only a certain (limited) set of exception types.

+1
source
 //inversion of the problem :) struct base_exception : public std::exception { std::list<base_exception*> snowball; base_exception() { } void add(base_exception* e) { snowball.push_back(e); } }; void func2() { func2_exception e; e.add(new func2_exception()); throw e; } void func1() { try { func2(); } catch(base_exception& e) { e.add(new func1_exception()); throw e; } } int main(void) { try { func1(); } catch(base_exception& e) { std::cout << "Got exception" << std::endl; //print info in the direct order of exceptions occurence foreach(base_exception* exception, e.snowball) { std::cout << exception->what(); std::cout << "next exception was:" << std::endl; } } } 

hmmm ...

0
source

One of the problems with internal exclusion is the ability to restart it while maintaining polymorphic behavior.

This can be (somewhat) facilitated by actually managing the lifetime of the exception and providing polymorphic copies.

 // Base class class exception: virtual public std::exception, private boost::noncopyable { public: virtual exception* clone() const = 0; virtual void rethrow() const = 0; // throw most Derived copy }; // ExceptionPointer class ExceptionPointer: virtual public std::exception { public: typedef std::unique_ptr<exception> pointer; ExceptionPointer(): mPointer() {} ExceptionPointer(exception* p): mPointer(p) {} ExceptionPointer(pointer p): mPointer(p) {} exception* get() const { return mPointer.get(); } void throwInner() const { if (mPointer.get()) mPointer->rethrow(); } virtual char* what() const { return mPointer.get() ? mPointer->what() : 0; } private: pointer mPointer; }; 

How to use?

 try { // some code } catch(exception& e) { throw ExceptionPointer(e.clone()); } // later on try { } catch(ExceptionPointer& e) { e.throwInner(); } 
0
source

As pointed out by others, boost :: exception is a good option. However, like all options that use the general approach of the base class, they rely on all thrown exceptions that are received from this base class. If your catch brokers need to add information to an exception from a third-party library, this will not work.

Perhaps for this it is enough to have intermediate catch handlers:

 catch (std::exception& ex) { std::string msg = ex.what(); msg.append(" - my extra info"); ex = std::exception(msg.c_str()); // slicing assignment throw; // re-throws 'ex', preserving it original type } 

This only works for std :: exception implementations that provide a constructor that accepts a string parameter (e.g. VC ++). The std :: exception constructor that takes a string is a non-standard extension.

0
source

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


All Articles