[英]C++: object slicing and exceptions
在一次采访中,我被问到为什么按价值捕获异常可能是一个问题,我回答说这会导致对象切片。 这就是我在互联网上找到的,例如: 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
对象进行切片,re throw
也会使用原始异常对象而不是切片副本。
来自http://en.cppreference.com/w/cpp/language/throw :
重新排列当前处理的异常。 放弃当前catch块的执行并将控制传递给下一个匹配的异常处理程序(但不会在同一个try块之后传递给另一个catch子句:它的compound-statement被认为已经'退出'), 重用现有的异常对象 :没有新的对象。 此表单仅在当前正在处理异常时允许(如果另外使用则调用std :: terminate)。 如果在构造函数上使用,则与函数try-block关联的catch子句必须通过rethrowing退出。
注意,如果你替换throw;
通过throw x;
,一个Base
实例将被抛出并且不会被捕获,导致调用std::abort()
。 实际上,切片的Derived
不能被未切割(这就是为什么我们通常不喜欢切片,除非它们是披萨切片)被catch (Derived)
。
作为结论,我坚持“按价值投掷,按(常)引用”) 。 在这个具体的例子中,你很好地捕捉切片值,但一般情况并非如此。 Serge Ballesta的回答提供了一个值得抓住的例子,导致了麻烦。 快速搜索您最喜爱的搜索引擎可以帮助您找到其他案例,其中捕获价值正在寻找麻烦。
另一个通过值捕获异常的问题是它需要异常的完整副本。 如果您接近StackOverflow条件(或已经处理一个条件),则可能处于无法执行复制的用例,并且无法执行catch子句。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.