C++:使用 va_list 类型作为类成员安全吗?
使用 va_list 类型作为类成员是否安全?
以下示例适用于 Solaris。它不需要在不同的操作系统之间移植。但它可以移植到未来的 Solaris 版本吗?硬件不同?不同的编译器?或者编译器选项?
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);
}
Is it safe to use a va_list type as a class member?
The below example works in Solaris. It doesn't need to be portable across different operating systems. But is it portable to future Solaris versions? Different HW? Different compilers? Or compiler options?
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不,您只能在
va_list
所引用的对象在作用域内(在函数本身中,或作为参数传递给其他函数)时使用 va_list,直到您调用>va_end
。您必须在从函数返回之前调用va_end
,之后va_list
将不再可用。从 C99,7.15.1.3 开始:“如果
va_end
宏在返回,行为未定义。”
在 C++11 中,考虑可变参数模板或 std::tuple 作为老式可变参数函数的类型安全替代方案。
No, you can only use the
va_list
while the objects it refers to are in scope (in the function itself, or passed as an argument to other functions), up to the point at which you callva_end
. You must callva_end
before returning from the function and, after that point, theva_list
is no longer usable.From C99, 7.15.1.3: "if the
va_end
macro is not invoked before thereturn, the behavior is undefined."
In C++11, consider variadic templates or
std::tuple
as type-safe alternatives to old-school variadic functions.这在任何平台上都不安全; va_list 指向堆栈参数,当构造函数返回时,该参数将被废弃。考虑使用更 C++ 类型安全的方法来存储参数;可能存储在
std::vector
中。This is not safe on any platform;
va_list
points to the stack arguments which will be obsolete when the constructor returns. Consider using a more C++-ish type-safe method to store the arguments; probably storing in astd::vector<std::string>
.只要所有
MyFormatString
实例在相应的可变参数函数返回之前被销毁,这可能会按预期工作。然而,根据 C 标准,它仍然是未定义的行为,因为需要在调用
va_copy()
的函数返回之前调用va_end()
,尽管我不知道在va_list
超出范围或相应的可变参数函数返回之前调用va_end()
不够的任何实现。如果您正在寻找符合标准的解决方案,请使用
va_list*
而不是列表的副本。不过,这将在从同一va_list
创建的MyFormatString
实例之间共享状态,因此它并不真正等效。如果您不想共享状态,则需要手动创建
va_list
的副本,并将指向该副本的指针传递给构造函数。使用指针有问题 在
va_list
是数组类型的平台上,可以通过使用 C++ 引用来避免这种情况(这显然没有在 C 标准中考虑,但应该根据指针语义进行操作)。This will probably work as expected as long as all
MyFormatString
instances are destroyed before the corresponding variadic function returns.However, it's still undefined behaviour according to the C standard as
va_end()
needs to be called before the function which invokedva_copy()
returns, though I don't know of any implementations where it doesn't suffice to callva_end()
before theva_list
goes out of scope or the corresponding variadic function returns.If you're looking for a standards-compliant solution, use a
va_list*
instead of a copy of the list. This will share state betweenMyFormatString
instances created from the sameva_list
, though, so it is not really equivalent.If you do not want to share state, you'll need to manually create a copy of the
va_list
and pass a pointer to that to your constructor.Using pointers has issues on platforms where
va_list
is an array type, which can be avoided by using C++ references instead (which obviously aren't accounted for in the C standard, but should behave according to pointer semantics).