假設我有一些C 代碼,其中有一個try-catch塊,其中catch部分將觸發一個長跳:
#include <stdexcept>/span>
#include <stdio.h>
#include <setjmp.h>
void my_fun()
{
jmp_buf jump_buffer。
if (setjmp(jump_buffer))
return;
嘗試 {
std::string message;
message.resize(100)。
snprintf(&message[0], 100, "錯誤代碼%d
", 3)。)
throw std::runtime_error(message);
}
catch (std::runtime_error & e) {
longjmp(jump_buffer, 1) 。
}
}
由于std::runtime_error物件是在某處動態分配的,它是否會泄露為其分配的記憶體或字串?
uj5u.com熱心網友回復:
這個問題有點復雜。關于longjmp的有效性,該標準說:
如果用 catch 和 throw 取代 setjmp 和 longjmp 會呼叫任何具有自動存盤期限的物件的任何非實質性的析構器,那么 setjmp/longjmp 呼叫對就具有未定義的行為。
runtime_error有一個非瑣碎的析構器,所以問題是例外物件是否有 "自動存盤期限"。它沒有。這表明,longjmp應該是好的。
例外物件的潛在破壞點是:
當例外物件發生時,它可能會被銷毀。
當例外的活動處理程式通過除重新拋出以外的任何方式退出時,在處理程式中的例外宣告中所宣告的物件(如果有的話)被銷毀后,立即進行銷毀;
- 當例外的活動處理程式通過除重新拋出以外的任何方式退出時,在處理程式中的例外宣告中所宣告的物件(如果有的話)被銷毀后,立即進行銷毀。
當一個參考例外物件的 std::exception_ptr 型別的物件被銷毀時,在 std::exception_ptr 的析構器回傳之前。
longjmp不是 "重拋"。所以從理論上講,由于第1點的存在,這應該是沒有問題的。
盡管如此,千萬不要依賴這個。我非常懷疑 longjmp 的實作能否正確地處理這個問題,即使有些實作做到了,它也可能不是你可以期待的。
uj5u.com熱心網友回復:
實際上有一個關于這個特定情況的C 缺陷報告,http://wg21.link/cwg2361 。因此,現在,什么是正確的還沒有定論。
uj5u.com熱心網友回復:
你為什么要做這樣的事情,我不知道。 但這個問題很耐人尋味。我知道你不能跳入一個捕獲塊。 而跳出它(也是 goto :( )是允許的。
似乎例外在離開 catch 范圍后就被銷毀了。而且沒有任何泄漏。下面是測驗程式的輸出:
在測驗程式中,我們可以看到:
在測驗程式中,我們可以看到
scope: normal_try_catch::try entered
構建的例外
scope : normal_try_catch::try left
scope : normal_try_catch::catch entered
范圍 : normal_try_catch::catch left
例外被銷毀了
----------------------------
范圍:long_jump_catch::try entered
例外構建
scope : long_jump_catch::try left
scope : long_jump_catch::catch entered
scope : long_jump_catch::catch left
例外被銷毀了
scope : long_jump_catch::leave because of setjmp entered
scope : long_jump_catch::leave because of setjmp left
所以在跳轉之前,例外被清理掉了。
#include <stdexcept>
#include <iostream>
#include <string>
#include <setjmp.h>
class my_except :
public std::exception
{
public:
my_except()
{
std::cout << "例外構建" << std::endl;
}
~my_except()
{
std::cout << "exception destructed" << std::endl;
}
};
struct scope
{
explicit scope(const std::string& scope) :
m_scope{ scope }。
{
std::cout << "scope : " << m_scope << " entered" << std::endl。
}
~scope()
{
std::cout << "scope : " << m_scope << " left" < < std::endl;
}
private:
std::string m_scope;
};
void normal_try_catch()
{
try
{
scope s{ "normal_try_catch::try" }。
throw my_except()。
}
catch(const std::exception&)
{
scope s{ "normal_try_catch::catch" }。
}
}
void long_jump_catch()
{
jmp_buf jump_buffer。
if (setjmp(jump_buffer))
{
scope s{ "long_jump_catch::leave because of setjmp" }。
return;
}
try; return; }
{
scope s{ "long_jump_catch::try" }。
throw my_except()。
}
catch (const std::exception&)
{
scope s{ "long_jump_catch::catch" };
longjmp(jump_buffer, 1)。
}
}
int main()
{
normal_try_catch()。
std::cout << "----------------------------" << std::endl;
long_jump_catch()。
return 0;
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/320012.html
標籤:
上一篇:使用std::unique_ptr在這里有什么好處嗎?
下一篇:為什么最后才列印例外的堆疊跟蹤?
