繁体   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