![](/img/trans.png)
[英]How to handle an exception thrown from a function defined as noexcept?
[英]Handle an exception thrown from a CTOR?
TL;博士
我想做這樣的事情:
foo()
{
Y* p;
try {
p = new Y();
} catch {
//fix any problem that may have occured
}
// Now I know the object was fixed during catch or simply was created successfully.
p.do_something();
// win
}
我正在創建的對象是使用有時不可靠的永恆資源。 在沒有必要的預防措施的情況下嘗試分配是危險的。 如果確實失敗了,那么有些事情可以做。 然而,似乎拋出一個異常,不像我后面展示的switch語句,不允許我修復問題AFAIK。
我被建議從構造函數中拋出異常。 但是,我不明白這是如何證明有用的,因為我沒有看到如何處理該異常? 我做了一個搜索並找到了這個例子,但我不確定它是否真的是一個有用的可擴展方法來處理構造失敗。
示例代碼:
void f()
{
X x; //← if X::X() throws, the memory for x itself will not leak
Y* p = new Y(); //← if Y::Y() throws, the memory for *p itself will not leak
}
讓我們說在堆之前有更多的實例在p
之前分配。 他們不會因此而泄漏到記憶中嗎? 因此函數f
僅用於構造Y
的實例。 將“危險”建築移到另一種方法之外是不是總是更有用?
我通常做的事情:
X* x = new X(); //No dangerous operation
switch (x.init()) // init returns int
{
case ...
// Handle failed init() here
}
這有缺點嗎? 看起來更可靠。
您應該在每個成員上使用RAII (資源獲取是初始化)。 只有在構造函數完成時才會調用對象的析構函數。 這樣,如果只調用兩個成員的構造函數中的一個,則只調用該成員的析構函數,其中應執行任何清理。
class Locked_file_handle {
File_ptr p;
unique_lock<mutex> lck;
public:
X(const char* file, mutex& m)
:p{file, "rw"},
lck{m}
{}
// ..
};
如果在構造p之后但在lck之前發生了異常,那么將調用p而不是lck的析構函數。 這樣做會讓構造函數的作者放棄編寫顯式異常處理代碼。
資料來源:“C ++編程語言第4版”(Stroustrup)
編輯:所以在你的情況下,它看起來像這樣
public class YHandle {
Y* p;
YHandle() {
Y = new Y()
}
~YHandle() {
delete Y;
}
}
foo() {
YHandle p = YHandle();
p.do_something();
} // p is deleted here
您的示例是安全的,因為如果c'tor拋出異常,則在傳遞異常之前釋放為無法構造的對象分配的內存。 當異常退出f
范圍時,堆棧被展開。
如果一個半構造並隨后擁有它的成員和基礎被破壞的對象被返回到調用范圍,則該范圍無法確定如何正確地釋放該內存,所以幸運的是,這不是做完了。
如果在同一函數中在堆上構造其他對象,則通常的規則適用。 原則上,這里不需要特殊情況的c'tor調用,只是假裝拋出的語句是常規函數調用。
如果拋出可能導致泄漏,那么您負責刪除分配
你可以像這樣滾動異常:
void f()
{
X x; //← if X::X() throws, the memory for x itself will not leak
Y* p;
try{
p = new Y(); //← if Y::Y() throws, the memory for *p itself will not leak
} catch(exception &e){
///clean what you need
throw e;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.