将va_list类型用作类成员是否安全?
以下示例适用于Solaris。它不需要可以跨不同的操作系统移植。但是它可以移植到未来的Solaris版本吗?不同的HW?不同的编译器?还是编译器选项?
class MyFormatString
{
public:
MyFormatString(const char* formatString, va_list varg);
~MyFormatString() { va_end(mVarg); }
// ...
// provide some util functions to operate on the format string
// ...
private:
string mFormatString;
va_list mVarg;
};
MyFormatString::MyFormatString(const char* fmt, va_list varg)
{
if (fmt)
mFormatString=fmt;
va_copy(mVarg, varg);
}
答案 0 :(得分:6)
不,你只能使用va_list
而它所引用的对象在范围内(在函数本身中,或作为参数传递给其他函数),直到你调用va_end
为止。 1}}。在从函数返回之前,必须调用va_end
,在此之后,va_list
不再可用。
从C99,7.15.1.3:“如果在{之前}没有调用va_end
宏
返回,行为未定义。“
在C ++ 11中,将可变参数模板或std::tuple
视为旧式可变参数函数的类型安全替代方法。
答案 1 :(得分:3)
这在任何平台上都不安全; va_list
指向堆栈参数,这些参数在构造函数返回时将过时。考虑使用更多C ++ - ish类型安全的方法来存储参数;可能存储在std::vector<std::string>
。
答案 2 :(得分:0)
只要在相应的可变参数函数返回之前销毁所有MyFormatString
实例,这可能会按预期工作。
然而,根据C标准,它仍然是未定义的行为,因为在调用va_end()
的函数返回之前需要调用va_copy()
,尽管我不知道它没有的任何实现在va_end()
超出范围或相应的可变参数函数返回之前调用va_list
就足够了。
如果您正在寻找符合标准的解决方案,请使用va_list*
而不是列表的副本。这将分享从同一MyFormatString
创建的va_list
个实例之间的状态,因此它实际上并不等同。
如果您不想共享状态,则需要手动创建va_list
的副本,并将指针传递给构造函数。
在va_list
是数组类型的平台上使用指针has issues,这可以通过使用C ++引用来避免(显然在C标准中没有考虑到,但应该根据指针语义)。