我有一个基于 printf
样式格式的日志记录框架:
void Logger::debug(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
this->output(DebugLevel, fmt, args);
va_end(args);
}
如果 Logger::output
抛出异常,编译器是否会正确展开堆栈,或者我是否需要在捕获条款?这可以改为 RAII,还是 va_end
太神奇了?如果可能,请包括对标准的引用。
最佳答案
不,他们不能。因为它们是宏而不能的推理是愚蠢的。宏可以毫无问题地从构造函数和析构函数中使用。然而,va_start
和 va_end
有特定要求,必须从同一函数调用它们。将它们移动到单独的函数是无效的。 C++ 指的是 C 标准,C 标准表示“每次调用 va_start
和 va_copy
宏都应与同一函数中相应的 va_end
宏调用相匹配。” (7.15.1) 如果你调用va_end
从辅助类的析构函数,它可能有效,也可能无效。由于不符合标准要求,因此行为未定义。
编辑:至于另一个问题,你需要va_end
吗?在抛出异常时,可以提出一个合理的论点,即“调用 va_end
宏”实际上并不要求代码到达调用该宏的位置(因为宏调用严格来说是编译时-only action),但它强烈表明你确实需要它。所以是的,使用 try
/catch
如果有可能出现异常(exception)情况。 C99 基本原理在其对 va_copy
的描述中简要说明那va_start
可以分配内存。 (我知道没有实际这样做的实现。)在这样的实现中,va_end
然后将释放该内存,因此跳过 va_end
会导致内存泄漏。
关于c++ - 抛出异常时是否需要 va_end?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11645282/