C:对象切片和异常
作者:互联网
在一次采访中,我被问到为什么按价值捕获异常可能是一个问题,我回答说这会导致对象切片.这就是我在互联网上找到的,例如:https://www.viva64.com/en/w/v746/
但是现在我正在尝试进行实验,但是在按值捕获时我找不到切片的示例.切片的常规场景(不是例外)是这样的:
Derived d1;
Derived d2;
Base& b1 = d1;
Base& b2 = d2;
b1 = b2;
在最后一行中调用Base的赋值运算符,它只复制Derived对象的Base部分.因此,b1的基础部分是从d2复制的,而b1的派生部分是从d2复制的.坏.
但是,当按价值捕获异常时,这怎么会发生?
我尝试了这个代码(同时使用:g和Sun CC编译器):
struct Base
{
virtual void print() const
{
cout << "{ Base: " << m << " }" << endl;
}
Base(int _m = 0) : m(_m) {}
int m;
};
struct Derived : Base
{
Derived(int _m = 0, int _n = 0) : Base(_m), n(_n) {}
void print() const
{
cout << "{ Base: " << m << ", Derived: " << n << " }" << endl;
}
int n;
};
int main()
{
try
{
try
{
throw Derived(3, 300);
}
catch(Base x)
{
cout << "Inner catch: ";
x.print();
throw;
}
}
catch(Derived y)
{
cout << "Outer catch: ";
y.print();
}
}
输出是:
Inner catch: { Base: 3 }
Outer catch: { Base: 3, Derived: 300 }
所以我抛出Derived异常,捕获它的Base BY VALUE并重新抛出,然后捕获Derived BY VALUE并且一切正常,没有任何切片.
那个怎么样?
并且有人可以提供捕获BY VALUE时的切片示例吗?
解决方法:
尽管catch(Base)会对抛出的Derived对象进行切片,但rethrow使用原始异常对象而不是切片副本.
从http://en.cppreference.com/w/cpp/language/throw开始:
Rethrows the currently handled exception. Abandons the execution of the current catch block and passes control to the next matching exception handler (but not to another catch clause after the same try block: its compound-statement is considered to have been ‘exited’), reusing the existing exception object: no new objects are made. This form is only allowed when an exception is presently being handled (it calls std::terminate if used otherwise). The catch clause associated with a function-try-block must exit via rethrowing if used on a constructor.
注意,如果你替换throw;通过throw x ;,将抛出一个Base实例并且不会捕获,导致调用std :: abort().实际上,切片的衍生物不能被未切割(这就是为什么我们通常不喜欢切片,除非它们是披萨切片)被catch(Derived)捕获.
作为结论,我坚持“按价值投掷,按(常)引用”).在这个具体的例子中,你很好地捕捉切片值,但一般情况并非如此. Serge Ballesta’s answer提供了一个导致麻烦的价值追赶的例子.快速搜索您最喜爱的搜索引擎可以帮助您找到其他案例,其中捕获价值正在寻找麻烦.
标签:rethrow,object-slicing,c,exception,exception-handling 来源: https://codeday.me/bug/20190731/1587270.html