典型示例:
void foo(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
// might throw, might not. who knows.
bar(fmt, args);
// uh-oh...
va_end(args);
}
这是一个坏主意,即在c ++中使用va_list
是不常见的吗?如果我将bar
包裹在try-catch中,这有帮助吗?会有什么替代方案?
答案 0 :(得分:4)
C ++标准遵循va_start
等规范的C标准。 C标准有这样说:
7.15.1p1 ... va_start和va_copy宏的每次调用都应与相同函数中va_end宏的相应调用相匹配。
因此,如果您在调用va_start
之后但在va_end
之前以任何方式退出该函数,则您的程序会显示未定义的行为。
是的,将bar
包裹在try/catch
中会有所帮助。
答案 1 :(得分:3)
C ++标准将此推迟到C标准。
C99(草案)7.15.1 / 1告诉我们:
每次调用va_start和va_copy宏都应匹配 在同一个函数中相应调用va_end宏。
因此,如果bar
抛出,则无法执行va_end
并且您的程序具有未定义的行为。如果您添加try / catch以确保始终根据需要调用va_end
,那么您应该没问题。但请记住,你不能将非POD作为varargs传递,所以如果你需要处理它们,你还是需要一种替代机制。
更像C ++的替代方案可能是插入运算符(operator<<
),如语言提供的各种iostream所示。
答案 2 :(得分:0)
如上所述,它是c标准的未定义行为。 然而,根据你的平台,marco可以编译成不同的东西,我看到它例如它只是args = 0;而va_list是一个char *;在这种情况下,似乎结束宏不做任何关键的事情。没有什么不好的事情发生,除非我不确定谁会解除分配,但我不知道他们在哪里被分配。
我不以任何方式推荐使用它,但有时候疯狂的东西是支持遗留代码所必需的。如果你可以使用try catch那么一定要这样做。