如何在C ++中模拟内部异常

时间:2010-05-14 17:52:28

标签: c++ exception

基本上我想在C ++中模拟.NET Exception.InnerException。我想从底层捕获异常并用另一个异常包装它并再次抛出到上层。这里的问题是我不知道如何将catched异常包装在另一个异常中。

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”成员。此外,我不确定即使在func2抛出之后,从func1抛出的临时对象是否仍然存在?

6 个答案:

答案 0 :(得分:3)

您还应该查看boost exception以了解包装的替代解决方案。

答案 1 :(得分:1)

  

另外我不确定是否   抛出的临时对象   func1即使在func2之后也会存活   扔?

没有。除非您使用throw;重新抛出异常。如果您只允许一些(有限的)异常类型集,则可以实现此目的。

答案 2 :(得分:0)

//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;
        }
    }
}

... hmmmm

答案 3 :(得分:0)

内部异常的一个问题是在保持多态行为的同时再次抛出它的可能性。

通过实际管理异常生命周期并提供多态副本,可以(稍微)缓解这种情况。

// 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();
}

答案 4 :(得分:0)

正如其他人所说,boost :: exception是一个不错的选择。但是,与使用公共基类方法的所有选项一样,它们依赖于从该基类派生的所有抛出异常。如果您的中间捕获处理程序需要向第三方库中的异常添加信息,则它将无法工作。

一个可能足够的选项就是拥有这样的中间捕获处理程序:

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's original type
}

这仅适用于std :: exception的实现,它提供了一个带字符串参数的构造函数(例如VC ++)。带字符串的std :: exception构造函数是非标准扩展名。

答案 5 :(得分:0)

自C ++ 11起,您有了新的选择:

  1. 您可以使用std::exception_ptr

    然后保留异常,直到最后一个exception_ptr 异常被破坏。

    struct base_exception : public std::exception
    {
        std::exception_ptr InnerException;
    
        base_exception() {}
        base_exception(std::exception& innerException)
         : InnerException(std::make_exception_ptr(innerException))
        {}
    
    };
    
  2. 或者您可以简单地使用std::nested_exception