c++ - 抛出异常时是否需要 va_end?

标签 c++ exception-handling variadic-functions printf

我有一个基于 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_startva_end有特定要求,必须从同一函数调用它们。将它们移动到单独的函数是无效的。 C++ 指的是 C 标准,C 标准表示“每次调用 va_startva_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/

相关文章:

c++ - 如何在不覆盖 C++ 的情况下保留指针的值

c++ - 如何在 makefile 中包含 -std=c++11 和 -lpthread?

c++ - 如何使用可变模板来包装可变数量的函数参数?

java - "Specializing"子类型的方法抛出检查异常?

c# - 如何避免 "Response.Redirect cannot be called in a Page callback"

c++ - 如何将可变模板参数字段的参数包限制为特定类型

使用 _* 的 varargs 的 Scala 类型归属导致错误

c++ - 如何将视频从我的应用程序流式传输到 Web?

c++ - 在 Qt 中捕获标签内的数字

javascript - 异步 node.js 调用中的错误处理