[英]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_start
和va_end
具有必須從同一函數調用它們的特定要求。 將它們移動到單獨的函數是無效的。 C ++指的是C標准,C標准說“ va_start
和va_copy
宏的每次調用都應該通過相同函數中va_end
宏的相應調用來匹配”。 (7.15.1)如果你從助手類的析構函數中調用va_end
,它可能會起作用,也可能不起作用。 由於它不符合標准的要求,因此行為未定義。
編輯:至於另一個問題,當拋出異常時,你是否需要va_end
,可以做出一個合法的參數“調用va_end
宏”實際上並不要求代碼到達你調用該宏的點(因為宏調用嚴格來說只是一個編譯時動作),但強烈暗示你確實需要它。 所以是的,如果異常是可能的話,請使用try
/ catch
。 C99基本原理在其對va_copy
描述中簡要說明了va_start
可以分配內存。 (我知道實際上沒有實現它的實現。)在這樣的實現上, va_end
然后將釋放該內存,因此跳過va_end
會導致內存泄漏。
沒有va_start
和va_end
是宏。 所以,他們不能成為RAII
的。 此外,例外情況不需要特別小心。
是的,這可以使用Boost.ScopeExit進行RAII ,即使va_start / va_end是宏的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.