3

Andrei Alexandrescu 在上一届C++ 和 Beyond 上就系统错误处理进行了演讲。我喜欢 Expected 模板模式并将其改编为 Visual Studio 2010,因为编译器目前不支持扩展联合。所以我写了一个 UnitTest 来检查一切是否正常。然后我想检查切片异常的检测是否有效。但它没有。

我不想在这里粘贴完整的代码,所以我试图减少这一点:

#include <iostream>
#include <string>
#include <exception>
#include <typeinfo>

class MyException : public std::exception
{
public:
  MyException()
    : std::exception()
  {}
  virtual const char* what() const { return "I come from MyException"; }
};

void hereHappensTheFailure()
{
 throw MyException();
}

template <class E>
void detector(const E& exception) 
{
  if (typeid(exception) != typeid(E)) 
  {
    std::cout << "Exception was sliced" << std::endl;
  }
  else
  {
    std::cout << "Exception was not sliced" << std::endl;
  }
}

int main()
{
  try
  {
    hereHappensTheFailure();
  }
  catch (std::exception ex) // intentionally catch by value to provoke the problem
  {
    detector(ex);
  }

  return 0;
}

但是没有检测到切片。那么我的测试是否有错误,这不适用于 VS2010 还是模式最终不起作用?(刚刚编辑,因为ideone上的 gcc 4.7.2不喜欢它)提前非常感谢!

4

2 回答 2

4

你的逻辑不正确。切片将异常从 MyException 转换为 std::exception。由于您让模板自动检测类型,因此它将选择与参数相同的类型 - 它保证是相同的。

改为这样称呼它:

detector<MyException>(ex);
于 2013-06-20T19:05:06.007 回答
0

我想,实现这一点的唯一方法是使用运行时多态异常:将虚函数添加到您的异常类中,可能只是返回 this 指针,您将能够区分拼接对象和未拼接对象。像这样:

class B;
class A {
    virtual B* toB() { return NULL; }
};
class B {
    B* toB() { return this; }
};

稍后,您可以对可能是 B 对象的任何 A 对象执行以下操作:

class A* foo = bar();
class B* fooB = foo->toB();
if(fooB) {
    //whatever
}

只要你的类中没有任何虚函数,C++ 实际上就禁止你注意到拼接,因为它断言对象中不会出现虚函数表指针以确保与 C 结构的兼容性. 但是需要那个指针来区分这两种情况。

但是请注意,只要您不使用“new”创建异常对象,我不确定这是否会起作用。如果您的异常被复制到基类类型的变量中,则生成的对象肯定是该基类类型,而不是创建它的派生类型。不过,“throw new MyException()”应该可以工作。

于 2013-06-20T19:20:23.323 回答