CppCoreGuidelines F.55 规避 va_arg
19 July 2022
F.55: Don’t use va_arg
arguments
理由
从va_arg
读取参数的时候,我们假设实际参数类型是正确设置的。传递变长参数的时候,我们假定函数会正确解析参数类型。但是两种假定都不一定可靠。
例子
// -*- compile-command: "g++ -std=c++20 code.cpp && ./a"; -*- #include <iostream> #include <gsl/gsl> #include <cstdarg> using namespace std; using namespace gsl; int sum(int cnt ...) { int result = 0; va_list list; va_start(list, cnt); while (cnt > 0) { cnt--; result += va_arg(list, int); // BAD, assumes it will be passed ints } va_end(list); return result; } int main() { cout << sum(2, 3, 2) << endl; // ok cout << sum(2, 3.14159, 2.71828) << endl; // BAD, undefined }
5 -2050589186
如果用C++17的折叠表达式(fold expression)对 Args
进行折叠展开,就比较灵活了:
// -*- compile-command: "g++ -std=c++20 code.cpp && ./a"; -*- #include <iostream> #include <gsl/gsl> using namespace std; using namespace gsl; template<class ...Args> auto sum(Args... args) // GOOD, and much more flexible { return (... + args); // note: C++17 "fold expression" } int main() { cout << sum(3, 2) << endl; // ok: 5 cout << sum(3.14159, 2.71828) << endl; // ok: ~5.85987 cout << sum(1, 2, 3, 4.8) << endl; cout << sum(string("hello"), string(" "), string("world")); }
5 5.85987 10.8 hello world
其他方法
- 重载( overloading )
- 可变参数模板(variadic templates)
- 变体参数(variant arguments)
- 初始化列表(initializer_list)
注意
声明一个...
参数,表示接收所有参数,就可以避免写明实际多少参数,减少不必要的函数重载。
强化
- 如果代码中使用了
va_list
,va_start
,va_arg
,对其进行诊断。 - 如果以
va_arg
的形式传递多个参数给函数,但是没指明什么类型,考虑是否可以通过重载明确参数类型。