[英]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.