假设你有一个只调用C函数的C ++函数,比如
int ClearTheBin()
{
int result = SHEmptyRecycleBinW(
nullptr,
nullptr,
SHERB_NOCONFIRMATION |
SHERB_NOPROGRESSUI |
SHERB_NOSOUND);
if (SUCCEEDED(result) ||
result == E_UNEXPECTED) // Already empty
{
return 0;
}
return result;
}
显然有zillion different things可能会对C函数的调用出错,但由于C缺少异常,因此这些错误将存储在生成的代码中。我的问题是:这些函数应该被声明为noexcept
吗?即使该方法无法抛出,也可能给读者带来错误的印象"这个功能没有任何问题,我可以认为它是100%可靠的," 因为noexcept
函数通常意味着什么。
您对此事的想法是什么?
答案 0 :(得分:3)
“此功能没有任何问题,我可以认为它是100% 可靠“
我不会那么快地假设。通常,如果我看到一个标记为noexcept
的函数,我倾向于寻找可以给我错误的替代方法,如布尔状态,某种全局错误检索函数,成功/失败返回值,类似那。只有缺乏这一点,并且可能面对不会产生副作用的功能,我才能做出这样的假设。
在你的情况下,你得到了整个错误代码的功能,所以很明显只要看一眼界面文档应该告诉我事情可能会出错,但noexcept
告诉我这些特殊情况不会(或至少不应)以例外形式向我(来电者)报告。
应用noexcept
一般情况下,安全方面似乎不愿意使用noexcept
。例如,std::string
对该函数的单一介绍,现在它可以抛出,只有noexcept
会将其转换为终止而不是我们可以捕获的东西。保证函数将永远不会抛出接口/设计级别是一个很难确保实际混合C ++代码的任何东西,特别是在任何随机同事可能引入的团队设置中(可能是紧缩)一天)一些随机的C ++函数调用或对象可以抛出这个函数。
无法投掷
在某些情况下,实际上很容易做出这种保证。一个例子是noexcept
函数,它有自己的try/catch
块,函数所做的一切都包含在其中。如果捕获到异常,请将其转换为某种错误代码并返回该异常。在这些情况下,try/catch
保证函数将吞下异常并且不会将其泄漏到外部世界。这里应用noexcept
变得很容易,因为函数不能抛出。
无法正确投掷
noexcept
不需要太多考虑的另一个例子是在一个函数的情况下,如果抛出则应该被认为是破坏的。一个示例是一个API函数,它跨SDK的模块边界调用,旨在允许使用任何编译器构建插件。因为我们不应该跨越模块边界,特别是在这种情况下,抛出已经是UB并且不应该完成。在这种情况下,noexcept
可以很容易地应用,因为函数的正确行为,按照设计,应该永远不会抛出。
如果有疑问,请将其删除。
在你的情况下,如果有疑问,我建议不予理会。使用noexcept
并且无意中抛弃了函数并终止程序,你可能会犯更多错误。例外情况是,如果您能够确保此ClearTheBin
函数总是仅使用C,则不会operator new
(或至少只有nothrow
版本),没有dynamic_casts
,没有标准的库等。除非你能为现在和将来做出这种硬接口级别的保证,否则在安全方面似乎是错误的。
答案 1 :(得分:2)
noexcept
从来没有打算意味着"什么都不会出错"。 noexcept
只是意味着函数不会抛出C ++异常。它绝不意味着函数在某种程度上不受其他类型问题的影响,例如未定义的行为。
所以,是的,如果您的所有函数都调用C函数,那么从正式的角度来看,声明noexcept
是完全合理的事情。
如果您个人希望制定自己的约定,noexcept
意味着更多,例如" 100%可靠的功能" (假设这样的事情甚至存在),那么你可以自由地这样做。但这成为你自己惯例的问题,而不是语言规范。