是否有可能在按值捕获后检测异常的切片?

时间:2013-06-20 18:45:06

标签: c++ exception c++11

Andrei Alexandrescu在上一次C++ and Beyond regarding systematic error handling举行了一次演讲。 我喜欢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不喜欢它) 非常感谢提前!

2 个答案:

答案 0 :(得分:4)

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

这样称呼它:

detector<MyException>(ex);

答案 1 :(得分: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”创建异常对象,我就不确定这是否有效。如果将异常复制到基类类型的变量中,则生成的对象肯定是该基类类型,而不是从其创建的派生类型。但是,抛出新的MyException()应该可行。