在C++?中慎用setjmp和longjmp解析
前言
setjmp和longjmp 是 C 語(yǔ)言中一個(gè)很強(qiáng)大的函數(shù)!
setjmp
和longjmp
是C語(yǔ)言中用于實(shí)現(xiàn)非局部跳轉(zhuǎn)的函數(shù)。它們通常用于處理錯(cuò)誤和異常情況,尤其是在C++的異常處理機(jī)制不可用或不適用的情況下。
setjmp
函數(shù)用于保存當(dāng)前的程序執(zhí)行環(huán)境,包括程序計(jì)數(shù)器、棧指針、寄存器等信息。這些信息被保存在一個(gè)類型為jmp_buf
的變量中。setjmp
函數(shù)的返回值取決于它是如何被調(diào)用的。如果是直接調(diào)用,它返回0;如果是由longjmp
函數(shù)調(diào)用,它返回longjmp
的第二個(gè)參數(shù)。
#include <setjmp.h> jmp_buf env; if (setjmp(env) == 0) { // This is the return from the direct call to setjmp. // Do something... } else { // This is the return from the call to longjmp. // Handle the error or exception... }
longjmp
函數(shù)用于恢復(fù)由setjmp
保存的程序執(zhí)行環(huán)境。當(dāng)調(diào)用longjmp
時(shí),程序會(huì)立即跳轉(zhuǎn)到最近一次調(diào)用setjmp
的位置,并使setjmp
返回longjmp
的第二個(gè)參數(shù)。注意,longjmp
不會(huì)返回,它會(huì)直接改變程序的控制流。
#include <setjmp.h> jmp_buf env; void foo() { // An error or exception occurs... longjmp(env, 1); } int main() { if (setjmp(env) == 0) { foo(); } else { // Handle the error or exception... } return 0; }
雖然setjmp
和longjmp
在某些情況下可能很有用,但它們也有很多潛在的問(wèn)題。例如,它們不會(huì)正確處理C++的對(duì)象析構(gòu)和異常處理機(jī)制,可能會(huì)導(dǎo)致資源泄露和未定義行為。因此,除非你非常清楚你在做什么,否則最好避免使用setjmp
和longjmp
。
longjmp 跳轉(zhuǎn)的資源釋放過(guò)程
對(duì)于C/C++中的基本類型(如int、double等)和在棧上分配的對(duì)象,當(dāng)它們的作用域結(jié)束時(shí),它們會(huì)自動(dòng)被銷毀,不需要手動(dòng)釋放。這是因?yàn)樗鼈兊纳芷谂c它們的作用域綁定。當(dāng)你離開一個(gè)作用域時(shí),該作用域中的所有局部變量都會(huì)被自動(dòng)銷毀。
當(dāng)你使用longjmp
進(jìn)行非局部跳轉(zhuǎn)時(shí),你實(shí)際上是在改變程序的控制流,跳出了某些變量的作用域。這意味著這些變量的生命周期結(jié)束,它們會(huì)被自動(dòng)銷毀。
因此,對(duì)于基本類型和在棧上分配的對(duì)象,即使你使用longjmp
進(jìn)行非局部跳轉(zhuǎn),也不會(huì)導(dǎo)致內(nèi)存泄漏,因?yàn)樗鼈儠?huì)在作用域結(jié)束時(shí)被自動(dòng)銷毀。
然而,對(duì)于動(dòng)態(tài)分配的內(nèi)存和其他需要手動(dòng)管理的資源(如打開的文件、鎖定的互斥鎖等),你需要確保在調(diào)用longjmp
之前正確地釋放它們,否則可能會(huì)導(dǎo)致資源泄漏。
C++ 使用setjmp和longjmp 的危險(xiǎn)性
在C++中,使用setjmp
和longjmp
進(jìn)行非局部跳轉(zhuǎn)是可能的,但并不推薦。這是因?yàn)?code>setjmp和longjmp
不會(huì)正確處理C++的對(duì)象析構(gòu)和異常處理機(jī)制,可能會(huì)導(dǎo)致資源泄露和未定義行為。
當(dāng)你調(diào)用longjmp
時(shí),它會(huì)立即跳轉(zhuǎn)到最近的setjmp
位置,而不會(huì)執(zhí)行在這兩個(gè)位置之間的任何代碼。這意味著如果你在setjmp
和longjmp
之間創(chuàng)建了任何對(duì)象,這些對(duì)象的析構(gòu)函數(shù)不會(huì)被調(diào)用,可能會(huì)導(dǎo)致資源泄露。同樣,如果你在setjmp
和longjmp
之間拋出了任何異常,這些異常也不會(huì)被捕獲。
我擁有地址能訪問(wèn)之前的數(shù)據(jù)么?
當(dāng)你使用longjmp
進(jìn)行非局部跳轉(zhuǎn)時(shí),你實(shí)際上是在改變程序的控制流,跳出了某些變量的作用域。這意味著這些變量的生命周期結(jié)束,它們應(yīng)該被銷毀。然而,由于longjmp
的工作方式,這些變量的析構(gòu)函數(shù)不會(huì)被調(diào)用。這可能會(huì)導(dǎo)致資源泄漏,如果這些變量是類的對(duì)象,并且在它們的析構(gòu)函數(shù)中管理了一些資源(如動(dòng)態(tài)分配的內(nèi)存)。
然而,即使這些變量的析構(gòu)函數(shù)沒有被調(diào)用,你仍然不應(yīng)該再訪問(wèn)這些變量。這是因?yàn)樗鼈兊纳芷谝呀?jīng)結(jié)束,它們的狀態(tài)已經(jīng)變得未定義。如果你試圖訪問(wèn)一個(gè)生命周期已經(jīng)結(jié)束的變量,你可能會(huì)遇到各種問(wèn)題,如無(wú)效的內(nèi)存訪問(wèn)錯(cuò)誤、未定義的行為等。
因此,即使你在longjmp
之后仍然有一個(gè)指向?qū)ο蟮闹羔?,你也不?yīng)該再使用這個(gè)指針,因?yàn)樵搶?duì)象的狀態(tài)已經(jīng)變得未定義。在C++中,一旦一個(gè)對(duì)象的生命周期結(jié)束,你就應(yīng)該停止使用該對(duì)象。
可以加一個(gè)標(biāo)志位,在跳轉(zhuǎn)后釋放所有內(nèi)存么?
在理論上,你可以在調(diào)用
longjmp
之前設(shè)置一個(gè)標(biāo)志位,然后在longjmp
之后檢查這個(gè)標(biāo)志位,如果它被設(shè)置了,那么你就釋放所有的資源。然而,在實(shí)踐中,這可能會(huì)非常復(fù)雜和容易出錯(cuò)。首先,你需要確保你能夠正確地追蹤所有的資源。這可能包括動(dòng)態(tài)分配的內(nèi)存、打開的文件、鎖定的互斥鎖、創(chuàng)建的線程等等。在一個(gè)大型的程序中,追蹤所有的資源可能會(huì)非常困難。
其次,你需要確保你能夠在任何時(shí)候安全地釋放這些資源。這可能需要你在程序的每個(gè)部分都添加額外的錯(cuò)誤處理代碼,以處理可能的
longjmp
。這可能會(huì)使你的代碼變得非常復(fù)雜和難以維護(hù)。最后,即使你能夠正確地追蹤和釋放所有的資源,
longjmp
仍然可能導(dǎo)致未定義行為。這是因?yàn)?code>longjmp不會(huì)正確地處理C++的對(duì)象析構(gòu)和異常處理機(jī)制。如果你在setjmp
和longjmp
之間創(chuàng)建了任何對(duì)象,這些對(duì)象的析構(gòu)函數(shù)不會(huì)被調(diào)用,可能會(huì)導(dǎo)致資源泄露。同樣,如果你在setjmp
和longjmp
之間拋出了任何異常,這些異常也不會(huì)被捕獲。因此,雖然在理論上你可以使用
longjmp
來(lái)處理段錯(cuò)誤,但在實(shí)踐中這通常是一個(gè)非常糟糕的主意。如果你的程序發(fā)生段錯(cuò)誤,最好的做法通常是盡快終止程序,然后使用調(diào)試器來(lái)找出問(wèn)題的原因。
全是堆上的對(duì)象也會(huì)泄漏么?
即使所有的數(shù)據(jù)都存儲(chǔ)在棧上,使用
setjmp
和longjmp
進(jìn)行非局部跳轉(zhuǎn)仍然可能導(dǎo)致問(wèn)題。這是因?yàn)?code>setjmp和longjmp
不會(huì)正確處理C++的對(duì)象析構(gòu)和異常處理機(jī)制。當(dāng)你調(diào)用
longjmp
時(shí),它會(huì)立即跳轉(zhuǎn)到最近的setjmp
位置,而不會(huì)執(zhí)行在這兩個(gè)位置之間的任何代碼。這意味著如果你在setjmp
和longjmp
之間創(chuàng)建了任何對(duì)象,這些對(duì)象的析構(gòu)函數(shù)不會(huì)被調(diào)用,可能會(huì)導(dǎo)致資源泄露。同樣,如果你在setjmp
和longjmp
之間拋出了任何異常,這些異常也不會(huì)被捕獲。此外,即使你的數(shù)據(jù)都存儲(chǔ)在棧上,你仍然需要確保你能夠在任何時(shí)候安全地釋放這些數(shù)據(jù)。這可能需要你在程序的每個(gè)部分都添加額外的錯(cuò)誤處理代碼,以處理可能的
longjmp
。這可能會(huì)使你的代碼變得非常復(fù)雜和難以維護(hù)。因此,雖然在理論上你可以使用
longjmp
來(lái)處理段錯(cuò)誤,但在實(shí)踐中這通常是一個(gè)非常糟糕的主意。如果你的程序發(fā)生段錯(cuò)誤,最好的做法通常是盡快終止程序,然后使用調(diào)試器來(lái)找出問(wèn)題的原因。
智能指針能避免longjmp的泄漏么?
智能指針在C++中主要用于自動(dòng)管理動(dòng)態(tài)分配的內(nèi)存,以防止內(nèi)存泄漏。它們并不能直接解決
longjmp
引發(fā)的問(wèn)題,因?yàn)?code>longjmp跳過(guò)了智能指針的析構(gòu)函數(shù),這可能會(huì)導(dǎo)致智能指針管理的內(nèi)存泄漏。然而,智能指針可以在某些情況下幫助你更安全地管理資源。例如,如果你有一個(gè)智能指針,你可以在
longjmp
之前手動(dòng)調(diào)用其reset
方法來(lái)釋放其管理的內(nèi)存。這樣,即使你跳過(guò)了智能指針的析構(gòu)函數(shù),也不會(huì)導(dǎo)致內(nèi)存泄漏。然而,這并不能解決所有的問(wèn)題。例如,如果你在
setjmp
和longjmp
之間創(chuàng)建了一個(gè)新的智能指針,你可能無(wú)法在longjmp
之前調(diào)用其reset
方法,因?yàn)槟銦o(wú)法預(yù)知longjmp
的發(fā)生。總的來(lái)說(shuō),雖然智能指針可以在某些情況下幫助你更安全地管理資源,但它們并不能完全解決
longjmp
引發(fā)的問(wèn)題。在C++中,最好的做法是避免使用longjmp
,并使用異常來(lái)進(jìn)行錯(cuò)誤處理。
C++ 中如何安全的使用setjmp和longjmp (如有問(wèn)題感謝指出)?
1.必須使用堆區(qū)內(nèi)存,棧區(qū)對(duì)象失去作用域必然會(huì)被釋放內(nèi)存,不調(diào)用析構(gòu)函數(shù)并不會(huì)影響內(nèi)存的釋放.
2.當(dāng)然你需要一直獲取堆區(qū)內(nèi)存的地址,才能在跳轉(zhuǎn)后重新聲明一個(gè)指針指向它.
到此這篇關(guān)于在C++ 中慎用setjmp和longjmp的文章就介紹到這了,更多相關(guān)C++ setjmp和longjmp內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用C語(yǔ)言提取子字符串及判斷對(duì)稱子字符串最大長(zhǎng)度
這篇文章主要介紹了使用C語(yǔ)言提取子字符串及判斷對(duì)稱子字符串最大長(zhǎng)度,文后附送了一道ACM競(jìng)賽題目,需要的朋友可以參考下2015-08-08c++中拷貝構(gòu)造函數(shù)的參數(shù)類型必須是引用
如果拷貝構(gòu)造函數(shù)中的參數(shù)不是一個(gè)引用,即形如CClass(const CClass c_class),那么就相當(dāng)于采用了傳值的方式(pass-by-value),而傳值的方式會(huì)調(diào)用該類的拷貝構(gòu)造函數(shù),從而造成無(wú)窮遞歸地調(diào)用拷貝構(gòu)造函數(shù)。因此拷貝構(gòu)造函數(shù)的參數(shù)必須是一個(gè)引用2013-07-07C/C++哈希表優(yōu)化LeetCode題解997找到小鎮(zhèn)的法官
這篇文章主要為大家介紹了C/C++哈希表優(yōu)化題解997找到小鎮(zhèn)的法官示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12