Elp*_*oca 5 c++ lambda exception variadic-functions
lambda的以下用法是错误的,脆弱的还是愚蠢的?它适用于VC++ 2012,但我担心有一些变量 - 参数/ lambda堆栈交互使得这很危险.
class
ArgumentException : public std::runtime_error
{
public:
ArgumentException(
const char* format_,
... )
: std::runtime_error(
[&]()
{
char buffer[2048];
va_list arguments;
va_start ( arguments, format_ );
int writtenCount = vsnprintf( buffer, 2048, format_, arguments );
va_end ( arguments );
return std::string(buffer);
}() )
{
}
};
Run Code Online (Sandbox Code Playgroud)
C++11 标准明确地va_list
通过以下方式提供支持宏:<cstdarg>
,但没有尝试限制它们的使用或(重新)定义它们的含义,因此我将转向C 标准。
\xc2\xa77.15.1.4 表示:
\n\n\n\n
void va_start(va_list ap,
参数N);
参数parmN是函数定义中变量参数列表中最右边参数的标识符(位于 之前的那个
\n, ...
)。如果参数parmN声明为register
存储类、函数或数组类型或与应用默认参数提升后产生的类型不兼容的类型来声明
在你的情况下,format_
不是一个参数(它是你的 lambda 中捕获的变量),并且被va_start
调用的函数甚至不是带有变量参数列表的函数,所以你可以说非常处于未定义的领域行为。更不用说C语言的参数提升规则无法处理引用类型,因此它无法正确处理以下事实:format_
不是直接指针的事实。
据我所知,在构造函数的初始化列表中使用可变参数在语法上是不可行的。(请参阅下面的这个人是谁做的。)但是,您可以使用可变参数模板将参数转发到“干净的”C 风格可变参数函数:
#include <cstdarg>\n#include <cstdio>\n#include <string>\n\nstd::string stringprintf(const char* format, ...)\n{\n char buffer[0x2000];\n va_list ap;\n va_start(ap, format);\n vsnprintf(buffer, sizeof buffer, format, ap);\n va_end(ap);\n return buffer;\n}\n\nclass ArgumentException : public std::runtime_error\n{\npublic:\n template<typename... T>\n ArgumentException(const char* format, T... arguments)\n : std::runtime_error(stringprintf(format, arguments...))\n { }\n};\n
Run Code Online (Sandbox Code Playgroud)\n还可以考虑使用<stdexcept>
\'sinvalid_argument
异常子类。