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不喜欢它) 非常感谢提前!
答案 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()应该可行。