В основном я хочу моделировать Исключение.NET. InnerException в C++. Я хочу поймать исключение из нижнего слоя и перенести его за другим исключением и броском снова к верхнему уровню. Проблема здесь, я не знаю, как перенести перехваченную исключительную ситуацию в другом исключении.
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 ?
}
}
В вышеупомянутом листинге кода я не уверен, как инициализировать участника "InnerException", когда нет никакого внутреннего исключения. Также я не уверен, выживет ли временный объект, который брошен от func1, даже после func2 бросок?
Вам также следует взглянуть на исключение ускорения для альтернативного решения для упаковки.
Также я не уверен, что временный объект, который выбрасывается из временный объект, который выбрасывается из func1, сохранится даже после выполнения func2 throw?
Нет. Если только вы не перебросите исключение с помощью throw;
. Вы могли бы реализовать это, если бы разрешили только некоторый (ограниченный) набор типов исключений.
//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;
}
}
}
хмммм ...
Одной из проблем с внутренним исключением является возможность его повторного вызова при сохранении полиморфного поведения.
Это можно (в некоторой степени) облегчить, если самостоятельно управлять временем жизни исключения и предоставлять полиморфные копии.
// 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;
};
Как использовать?
try
{
// some code
}
catch(exception& e)
{
throw ExceptionPointer(e.clone());
}
// later on
try
{
}
catch(ExceptionPointer& e)
{
e.throwInner();
}