从函数(不抛出函数)返回异常以进行消息格式化?

Return exception from function (not throw in function) for message formatting?

本文关键字:函数 格式化 异常 消息 返回      更新时间:2023-10-16

我有一个执行基本字符串格式化的函数,以生成错误描述字符串作为std::runtime_error的输入:

std::string errormsg(int i)
{
std::string str;
// .. do something with str
return str;
}

。这样:

void some_process(int x)
{
if (x < 0)
throw std::runtime_error(errmsg(x));
}

我的直觉是,这可以通过使用直接返回异常类型的函数来简化;使用更完整的示例:

template<typename ... Ts>
std::runtime_error error(const char * frmt, Ts ... args)
{
const int n = std::snprintf(nullptr, 0, frmt, args...);
std::vector<char> buff(n + 1);
std::snprintf(&buff[0], n + 1, frmt, args...);
return std::runtime_error(std::string(buff.data()));
}

。这简化为throw error("Error code %d", x).

但是我发现很难找到从包装器函数返回异常类型的代码示例。因此,上述情况是否被视为不良做法,或者不安全?

异常类型没有什么特别之处。它们与其他类型一样,只是它们应该作为例外被抛出。请考虑您可以throw任何类型的对象,而不仅仅是从std::exception继承的类型。

您没有找到示例的原因可能是,从std::runtime_error继承然后在需要时调用构造函数更为典型。类似的东西

struct my_runtime_error : std::runtime_error {
{
template<typename ... Ts>
my_runtime_error(const char * frmt, Ts ... args);
};

或者按照注释中的建议,编写一个返回void的函数,而不是throw异常本身:

template<typename ... Ts>
[[ noreturn ]] void throw_error(const char * frmt, Ts ... args)
{
const int n = std::snprintf(nullptr, 0, frmt, args...);
std::vector<char> buff(n + 1);
std::snprintf(&buff[0], n + 1, frmt, args...);
throw std::runtime_error(std::string(buff.data()));
}

用作

void some_process(int x)
{
if (x < 0)
throw_error(errmsg(x));
}

但是,这样做的缺点是始终从相同的函数而不是实际出现问题的位置抛出,如果我必须在这个和你的之间进行选择,我会选择你的解决方案。

PS:请注意,与标准库中的大多数其他类型的类型相比,std::exception及其后代是要继承的。std::exception确实有一个虚拟析构函数。