簡體   English   中英

拋出異常時是否需要va_end?

[英]Do I need to va_end when an exception is thrown?

我有一個基於printf樣式格式的日志框架:

void Logger::debug(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    this->output(DebugLevel, fmt, args);
    va_end(args);
}

如果Logger::output拋出,編譯器是否會正確展開堆棧,還是需要在catch子句中添加帶有va_end(args)的try / catch塊? 這能代替RAII'ed,或va_end過魔法是什么? 如果可能,請包括對標准的參考。

不,他們不能。 他們不能因為它們是宏的原因是愚蠢的。 宏可以從構造函數和析構函數中使用而沒有任何問題。 但是, va_startva_end具有必須從同一函數調用它們的特定要求。 將它們移動到單獨的函數是無效的。 C ++指的是C標准,C標准說“ va_startva_copy宏的每次調用都應該通過相同函數中va_end宏的相應調用來匹配”。 (7.15.1)如果你從助手類的析構函數中調用va_end ,它可能會起作用,也可能不起作用。 由於它不符合標准的要求,因此行為未定義。

編輯:至於另一個問題,當拋出異常時,你是否需要va_end ,可以做出一個合法的參數“調用va_end宏”實際上並不要求代碼到達你調用該宏的點(因為宏調用嚴格來說只是一個編譯時動作),但強烈暗示你確實需要它。 所以是的,如果異常是可能的話,請使用try / catch C99基本原理在其對va_copy描述中簡要說明了va_start可以分配內存。 (我知道實際上沒有實現它的實現。)在這樣的實現上, va_end然后將釋放該內存,因此跳過va_end會導致內存泄漏。

沒有va_startva_end是宏。 所以,他們不能成為RAII的。 此外,例外情況不需要特別小心。

是的,這可以使用Boost.ScopeExit進行RAII ,即使va_start / va_end是宏的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM