当抛出异常时,我需要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'd吗?还是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是宏的,也可以使用Boost.ScopeExit进行RAII。
没有va_start
和va_end
是宏。因此,它们不可能是RAII
。此外,对于例外情况不需要特别注意。
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 反转依赖于 end() 的迭代器
- std::multimap<std::chrono::milliseconds, T>::rbegin 在 MSVS-13 中指向 end()?
- 在C++中使用 Catch 测试框架编译错误"error: expected ';' at end of declaration list"
- remove(str.begin(), str.end(), );无法正常工作(我正在使用视觉工作室 2012)
- 在 ifcondition al中 find() C++ STL 中的 == a.end() 有什么用?
- 野牛/yacc 解析器在不被空格分隔时跳过 grammer - "unexpected $end"
- "错误 C0000:语法错误,令牌"<EOF>"处出现意外$end,并且不确定
- 了解向量中的 .begin 和 .end
- 如何实现链表的 end()?
- 使用 map.end() 访问 map 的最后一个元素
- C++ const char with .begin() and .end()
- 接收"Error compiling: 0:1(1): error: syntax error, unexpected $end" C++、GLSL、着色器文件
- 为什么 std::find( s.begin(), s.end(), val ) 比集合 s 的 s.find(val) 慢 1000 倍<int>?
- 如何使用vector.begin()和vector.end()遍历矩阵?
- 我当前实现的双向链表类是否需要重构迭代器 end() 功能?
- 创建一个简单的前向迭代器,该迭代器在循环缓冲区的"end"处自动换行
- 在不使用vector.end()的情况下迭代std::vector
- 编译代码时"[Warning] extra tokens at end of"