[英]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.